mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 11:39:22 +00:00
Merge branch 'main' into CW-292-Save-historical-fiat-API-rate
This commit is contained in:
commit
67bc9a7c9f
167 changed files with 5302 additions and 1871 deletions
3
.github/workflows/pr_test_build.yml
vendored
3
.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
|
||||||
|
@ -151,6 +151,7 @@ jobs:
|
||||||
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
||||||
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
|
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
|
||||||
|
echo "const quantexExchangeMarkup = '${{ secrets.QUANTEX_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
|
||||||
echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
|
echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
|
||||||
echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
||||||
|
|
||||||
|
|
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/quantex.png
Normal file
BIN
assets/images/quantex.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 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 +1 @@
|
||||||
Generic bug fixes and enhancements
|
Bug fixes and generic enhancements
|
|
@ -1,4 +1 @@
|
||||||
Hardware wallets support for Bitcoin, Ethereum and Polygon
|
|
||||||
Add Tron wallet
|
|
||||||
Security enhancements
|
|
||||||
Bug fixes and generic enhancements
|
Bug fixes and generic enhancements
|
|
@ -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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ class BitcoinReceivePageOption implements ReceivePageOption {
|
||||||
static const p2wsh = BitcoinReceivePageOption._('Segwit (P2WSH)');
|
static const p2wsh = BitcoinReceivePageOption._('Segwit (P2WSH)');
|
||||||
static const p2pkh = BitcoinReceivePageOption._('Legacy (P2PKH)');
|
static const p2pkh = BitcoinReceivePageOption._('Legacy (P2PKH)');
|
||||||
|
|
||||||
|
static const silent_payments = BitcoinReceivePageOption._('Silent Payments');
|
||||||
|
|
||||||
const BitcoinReceivePageOption._(this.value);
|
const BitcoinReceivePageOption._(this.value);
|
||||||
|
|
||||||
final String value;
|
final String value;
|
||||||
|
@ -17,6 +19,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,
|
||||||
|
@ -24,6 +27,24 @@ class BitcoinReceivePageOption implements ReceivePageOption {
|
||||||
BitcoinReceivePageOption.p2pkh
|
BitcoinReceivePageOption.p2pkh
|
||||||
];
|
];
|
||||||
|
|
||||||
|
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) {
|
||||||
case SegwitAddresType.p2tr:
|
case SegwitAddresType.p2tr:
|
||||||
|
@ -34,6 +55,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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,24 @@
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'dart:convert';
|
||||||
import 'package:convert/convert.dart';
|
|
||||||
|
|
||||||
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
|
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||||
|
import 'package:convert/convert.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
||||||
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
|
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||||
|
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
|
||||||
import 'package:cw_bitcoin/psbt_transaction_builder.dart';
|
import 'package:cw_bitcoin/psbt_transaction_builder.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
|
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
import 'package:ledger_flutter/ledger_flutter.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
|
||||||
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
|
|
||||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
|
||||||
import 'package:cw_core/wallet_info.dart';
|
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
|
||||||
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
|
||||||
|
|
||||||
part 'bitcoin_wallet.g.dart';
|
part 'bitcoin_wallet.g.dart';
|
||||||
|
|
||||||
|
@ -38,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!;
|
||||||
|
@ -61,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;
|
||||||
});
|
});
|
||||||
|
@ -83,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;
|
||||||
|
|
||||||
|
@ -108,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,
|
||||||
|
@ -122,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!)
|
||||||
|
@ -162,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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,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
|
||||||
|
@ -201,18 +221,38 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String> signMessage(String message, {String? address = null}) async {
|
||||||
|
if (walletInfo.isHardwareWallet) {
|
||||||
|
final addressEntry = address != null
|
||||||
|
? walletAddresses.allAddresses.firstWhere((element) => element.address == address)
|
||||||
|
: null;
|
||||||
|
final index = addressEntry?.index ?? 0;
|
||||||
|
final isChange = addressEntry?.isHidden == true ? 1 : 0;
|
||||||
|
final accountPath = walletInfo.derivationInfo?.derivationPath;
|
||||||
|
final derivationPath = accountPath != null ? "$accountPath/$isChange/$index" : null;
|
||||||
|
|
||||||
|
final signature = await _bitcoinLedgerApp!
|
||||||
|
.signMessage(_ledgerDevice!, message: ascii.encode(message), signDerivationPath: derivationPath);
|
||||||
|
return base64Encode(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.signMessage(message, address: address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -332,7 +354,7 @@ class ElectrumClient {
|
||||||
// "hex": "00000020890208a0ae3a3892aa047c5468725846577cfcd9b512b50000000000000000005dc2b02f2d297a9064ee103036c14d678f9afc7e3d9409cf53fd58b82e938e8ecbeca05a2d2103188ce804c4"
|
// "hex": "00000020890208a0ae3a3892aa047c5468725846577cfcd9b512b50000000000000000005dc2b02f2d297a9064ee103036c14d678f9afc7e3d9409cf53fd58b82e938e8ecbeca05a2d2103188ce804c4"
|
||||||
// }
|
// }
|
||||||
Future<int?> getCurrentBlockChainTip() =>
|
Future<int?> getCurrentBlockChainTip() =>
|
||||||
call(method: 'blockchain.headers.subscribe').then((result) {
|
callWithTimeout(method: 'blockchain.headers.subscribe').then((result) {
|
||||||
if (result is Map<String, dynamic>) {
|
if (result is Map<String, dynamic>) {
|
||||||
return result["height"] as int;
|
return result["height"] as int;
|
||||||
}
|
}
|
||||||
|
@ -340,6 +362,12 @@ class ElectrumClient {
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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>(
|
||||||
|
@ -396,7 +424,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,17 +461,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
|
||||||
|
|
|
@ -28,6 +28,12 @@ Map<DerivationType, List<DerivationInfo>> electrum_derivations = {
|
||||||
description: "Standard BIP84 native segwit",
|
description: "Standard BIP84 native segwit",
|
||||||
scriptType: "p2wpkh",
|
scriptType: "p2wpkh",
|
||||||
),
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/86'/0'/0'",
|
||||||
|
description: "Standard BIP86 Taproot",
|
||||||
|
scriptType: "p2tr",
|
||||||
|
),
|
||||||
DerivationInfo(
|
DerivationInfo(
|
||||||
derivationType: DerivationType.bip39,
|
derivationType: DerivationType.bip39,
|
||||||
derivationPath: "m/0'",
|
derivationPath: "m/0'",
|
||||||
|
|
|
@ -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: data['inputAddresses'] as List<String>,
|
amount: data['amount'] as int,
|
||||||
outputAddresses: data['outputAddresses'] as List<String>,
|
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';
|
||||||
|
@ -24,15 +24,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()),
|
||||||
|
@ -45,7 +47,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,27 +87,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 =
|
||||||
|
@ -103,6 +149,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;
|
||||||
|
@ -129,6 +187,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;
|
||||||
|
|
||||||
|
@ -196,7 +256,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);
|
||||||
|
|
||||||
|
@ -221,12 +324,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());
|
||||||
|
@ -235,18 +396,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());
|
||||||
}
|
}
|
||||||
|
@ -272,7 +456,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());
|
||||||
|
@ -282,8 +466,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) {
|
||||||
|
@ -349,6 +532,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 !=
|
||||||
|
@ -371,4 +563,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 {}
|
||||||
|
|
|
@ -14,7 +14,6 @@ import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
import 'package:cw_bitcoin/litecoin_network.dart';
|
import 'package:cw_bitcoin/litecoin_network.dart';
|
||||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
|
||||||
part 'litecoin_wallet.g.dart';
|
part 'litecoin_wallet.g.dart';
|
||||||
|
@ -45,7 +44,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,
|
||||||
|
|
|
@ -15,7 +15,6 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
||||||
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,
|
||||||
|
|
|
@ -73,6 +73,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,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:
|
||||||
|
@ -79,11 +79,11 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: cake-update-v2
|
ref: cake-update-v3
|
||||||
resolved-ref: "01d844a5f5a520a31df5254e34169af4664aa769"
|
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:
|
||||||
|
@ -96,11 +96,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:
|
||||||
|
@ -197,6 +198,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:
|
||||||
|
@ -217,10 +226,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
|
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.1"
|
version: "1.18.0"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -241,10 +250,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:
|
||||||
|
@ -288,10 +297,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:
|
||||||
|
@ -346,10 +363,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:
|
||||||
|
@ -394,10 +411,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"
|
||||||
http_multi_server:
|
http_multi_server:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -442,19 +459,43 @@ 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:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker
|
||||||
|
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.0.0"
|
||||||
|
leak_tracker_flutter_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_flutter_testing
|
||||||
|
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
|
leak_tracker_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_testing
|
||||||
|
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
ledger_bitcoin:
|
ledger_bitcoin:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: HEAD
|
ref: HEAD
|
||||||
resolved-ref: b6ed573cbeb57d5f0d39dfe4254bf9d15b620ab6
|
resolved-ref: f819d37e235e239c315e93856abbf5e5d3b71dab
|
||||||
url: "https://github.com/cake-tech/ledger-bitcoin.git"
|
url: "https://github.com/cake-tech/ledger-bitcoin"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.1"
|
version: "0.0.2"
|
||||||
ledger_flutter:
|
ledger_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -483,34 +524,34 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
|
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.15"
|
version: "0.12.16+1"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "0.8.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.11.0"
|
||||||
mime:
|
mime:
|
||||||
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:
|
||||||
|
@ -547,34 +588,34 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.3"
|
version: "1.9.0"
|
||||||
path_provider:
|
path_provider:
|
||||||
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:
|
||||||
|
@ -619,10 +660,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:
|
||||||
|
@ -663,6 +704,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:
|
||||||
|
@ -712,10 +761,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:
|
||||||
|
@ -736,26 +785,35 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.10.0"
|
||||||
|
sp_scanner:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: "sp_v2.0.0"
|
||||||
|
resolved-ref: "62c152b9086cd968019128845371072f7e1168de"
|
||||||
|
url: "https://github.com/cake-tech/sp_scanner"
|
||||||
|
source: git
|
||||||
|
version: "0.0.1"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
stream_transform:
|
stream_transform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -784,10 +842,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
|
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1"
|
version: "0.6.1"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -820,30 +878,46 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
watcher:
|
vm_service:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vm_service
|
||||||
|
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "13.0.0"
|
||||||
|
watcher:
|
||||||
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
name: watcher
|
name: watcher
|
||||||
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
||||||
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:
|
||||||
|
@ -860,6 +934,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.0.6 <4.0.0"
|
dart: ">=3.3.0 <4.0.0"
|
||||||
flutter: ">=3.10.0"
|
flutter: ">=3.16.6"
|
||||||
|
|
|
@ -32,13 +32,21 @@ 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-update-v2
|
ref: cake-update-v3
|
||||||
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:
|
||||||
url: https://github.com/cake-tech/ledger-bitcoin.git
|
url: https://github.com/cake-tech/ledger-bitcoin
|
||||||
|
sp_scanner:
|
||||||
|
git:
|
||||||
|
url: https://github.com/cake-tech/sp_scanner
|
||||||
|
ref: sp_v2.0.0
|
||||||
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
@ -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-update-v2
|
ref: cake-update-v3
|
||||||
|
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 =
|
||||||
|
@ -253,7 +255,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
static CryptoCurrency fromString(String name, {CryptoCurrency? walletCurrency}) {
|
static CryptoCurrency fromString(String name, {CryptoCurrency? walletCurrency}) {
|
||||||
try {
|
try {
|
||||||
return CryptoCurrency.all.firstWhere((element) =>
|
return CryptoCurrency.all.firstWhere((element) =>
|
||||||
element.title.toLowerCase() == name &&
|
element.title.toLowerCase() == name.toLowerCase() &&
|
||||||
(element.tag == null ||
|
(element.tag == null ||
|
||||||
element.tag == walletCurrency?.title ||
|
element.tag == walletCurrency?.title ||
|
||||||
element.tag == walletCurrency?.tag));
|
element.tag == walletCurrency?.tag));
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -149,10 +149,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
|
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.1"
|
version: "1.18.0"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -331,6 +331,30 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.8.1"
|
version: "4.8.1"
|
||||||
|
leak_tracker:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker
|
||||||
|
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.0.0"
|
||||||
|
leak_tracker_flutter_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_flutter_testing
|
||||||
|
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
|
leak_tracker_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_testing
|
||||||
|
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -343,26 +367,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
|
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.15"
|
version: "0.12.16+1"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "0.8.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.11.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -407,10 +431,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.3"
|
version: "1.9.0"
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -564,26 +588,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.10.0"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
stream_transform:
|
stream_transform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -612,10 +636,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
|
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1"
|
version: "0.6.1"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -640,8 +664,16 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
watcher:
|
vm_service:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vm_service
|
||||||
|
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "13.0.0"
|
||||||
|
watcher:
|
||||||
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
name: watcher
|
name: watcher
|
||||||
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
||||||
|
@ -681,5 +713,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.0.0 <4.0.0"
|
dart: ">=3.2.0-0 <4.0.0"
|
||||||
flutter: ">=3.10.0"
|
flutter: ">=3.10.0"
|
||||||
|
|
|
@ -149,10 +149,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
|
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.2"
|
version: "1.18.0"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -338,6 +338,30 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.8.0"
|
version: "4.8.0"
|
||||||
|
leak_tracker:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker
|
||||||
|
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.0.0"
|
||||||
|
leak_tracker_flutter_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_flutter_testing
|
||||||
|
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
|
leak_tracker_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_testing
|
||||||
|
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -350,26 +374,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.16"
|
version: "0.12.16+1"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "0.8.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.11.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -406,10 +430,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.3"
|
version: "1.9.0"
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -571,18 +595,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
stream_transform:
|
stream_transform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -611,10 +635,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.0"
|
version: "0.6.1"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -639,6 +663,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
|
vm_service:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vm_service
|
||||||
|
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "13.0.0"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: "direct overridden"
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
|
@ -647,14 +679,6 @@ 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: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.1.4-beta"
|
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -688,5 +712,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.1"
|
version: "3.1.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.1.0-185.0.dev <4.0.0"
|
dart: ">=3.2.0-0 <4.0.0"
|
||||||
flutter: ">=3.7.0"
|
flutter: ">=3.7.0"
|
||||||
|
|
|
@ -53,10 +53,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
|
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.2"
|
version: "1.18.0"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -201,6 +201,30 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.7"
|
version: "0.6.7"
|
||||||
|
leak_tracker:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker
|
||||||
|
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.0.0"
|
||||||
|
leak_tracker_flutter_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_flutter_testing
|
||||||
|
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
|
leak_tracker_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_testing
|
||||||
|
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
lints:
|
lints:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -213,26 +237,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.16"
|
version: "0.12.16+1"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "0.8.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.11.0"
|
||||||
mobx:
|
mobx:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -245,10 +269,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.3"
|
version: "1.9.0"
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -362,18 +386,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -394,10 +418,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.0"
|
version: "0.6.1"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -414,14 +438,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
web:
|
vm_service:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: vm_service
|
||||||
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
|
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.4-beta"
|
version: "13.0.0"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -439,5 +463,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0+3"
|
version: "0.2.0+3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.1.0-185.0.dev <4.0.0"
|
dart: ">=3.2.0-0 <4.0.0"
|
||||||
flutter: ">=3.7.0"
|
flutter: ">=3.7.0"
|
||||||
|
|
|
@ -464,6 +464,16 @@ extern "C"
|
||||||
return strdup(get_current_wallet()->address(account_index, address_index).c_str());
|
return strdup(get_current_wallet()->address(account_index, address_index).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *get_cache_attribute(char *name)
|
||||||
|
{
|
||||||
|
return strdup(get_current_wallet()->getCacheAttribute(std::string(name)).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_cache_attribute(char *name, char *value)
|
||||||
|
{
|
||||||
|
get_current_wallet()->setCacheAttribute(std::string(name), std::string(value));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const char *seed()
|
const char *seed()
|
||||||
{
|
{
|
||||||
|
|
|
@ -154,3 +154,7 @@ typedef freeze_coin = Void Function(Int32 index);
|
||||||
typedef thaw_coin = Void Function(Int32 index);
|
typedef thaw_coin = Void Function(Int32 index);
|
||||||
|
|
||||||
typedef sign_message = Pointer<Utf8> Function(Pointer<Utf8> message, Pointer<Utf8> address);
|
typedef sign_message = Pointer<Utf8> Function(Pointer<Utf8> message, Pointer<Utf8> address);
|
||||||
|
|
||||||
|
typedef get_cache_attribute = Pointer<Utf8> Function(Pointer<Utf8> name);
|
||||||
|
|
||||||
|
typedef set_cache_attribute = Int8 Function(Pointer<Utf8> name, Pointer<Utf8> value);
|
||||||
|
|
|
@ -154,3 +154,7 @@ typedef FreezeCoin = void Function(int);
|
||||||
typedef ThawCoin = void Function(int);
|
typedef ThawCoin = void Function(int);
|
||||||
|
|
||||||
typedef SignMessage = Pointer<Utf8> Function(Pointer<Utf8>, Pointer<Utf8>);
|
typedef SignMessage = Pointer<Utf8> Function(Pointer<Utf8>, Pointer<Utf8>);
|
||||||
|
|
||||||
|
typedef GetCacheAttribute = Pointer<Utf8> Function(Pointer<Utf8>);
|
||||||
|
|
||||||
|
typedef SetCacheAttribute = int Function(Pointer<Utf8>, Pointer<Utf8>);
|
||||||
|
|
|
@ -1,26 +1,24 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
import 'package:ffi/ffi.dart';
|
|
||||||
import 'package:cw_monero/api/structs/ut8_box.dart';
|
|
||||||
import 'package:cw_monero/api/convert_utf8_to_string.dart';
|
import 'package:cw_monero/api/convert_utf8_to_string.dart';
|
||||||
import 'package:cw_monero/api/signatures.dart';
|
|
||||||
import 'package:cw_monero/api/types.dart';
|
|
||||||
import 'package:cw_monero/api/monero_api.dart';
|
|
||||||
import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
|
import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
|
||||||
|
import 'package:cw_monero/api/monero_api.dart';
|
||||||
|
import 'package:cw_monero/api/signatures.dart';
|
||||||
|
import 'package:cw_monero/api/structs/ut8_box.dart';
|
||||||
|
import 'package:cw_monero/api/types.dart';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
int _boolToInt(bool value) => value ? 1 : 0;
|
int _boolToInt(bool value) => value ? 1 : 0;
|
||||||
|
|
||||||
final getFileNameNative = moneroApi
|
final getFileNameNative =
|
||||||
.lookup<NativeFunction<get_filename>>('get_filename')
|
moneroApi.lookup<NativeFunction<get_filename>>('get_filename').asFunction<GetFilename>();
|
||||||
.asFunction<GetFilename>();
|
|
||||||
|
|
||||||
final getSeedNative =
|
final getSeedNative = moneroApi.lookup<NativeFunction<get_seed>>('seed').asFunction<GetSeed>();
|
||||||
moneroApi.lookup<NativeFunction<get_seed>>('seed').asFunction<GetSeed>();
|
|
||||||
|
|
||||||
final getAddressNative = moneroApi
|
final getAddressNative =
|
||||||
.lookup<NativeFunction<get_address>>('get_address')
|
moneroApi.lookup<NativeFunction<get_address>>('get_address').asFunction<GetAddress>();
|
||||||
.asFunction<GetAddress>();
|
|
||||||
|
|
||||||
final getFullBalanceNative = moneroApi
|
final getFullBalanceNative = moneroApi
|
||||||
.lookup<NativeFunction<get_full_balanace>>('get_full_balance')
|
.lookup<NativeFunction<get_full_balanace>>('get_full_balance')
|
||||||
|
@ -38,41 +36,34 @@ final getNodeHeightNative = moneroApi
|
||||||
.lookup<NativeFunction<get_node_height>>('get_node_height')
|
.lookup<NativeFunction<get_node_height>>('get_node_height')
|
||||||
.asFunction<GetNodeHeight>();
|
.asFunction<GetNodeHeight>();
|
||||||
|
|
||||||
final isConnectedNative = moneroApi
|
final isConnectedNative =
|
||||||
.lookup<NativeFunction<is_connected>>('is_connected')
|
moneroApi.lookup<NativeFunction<is_connected>>('is_connected').asFunction<IsConnected>();
|
||||||
.asFunction<IsConnected>();
|
|
||||||
|
|
||||||
final setupNodeNative = moneroApi
|
final setupNodeNative =
|
||||||
.lookup<NativeFunction<setup_node>>('setup_node')
|
moneroApi.lookup<NativeFunction<setup_node>>('setup_node').asFunction<SetupNode>();
|
||||||
.asFunction<SetupNode>();
|
|
||||||
|
|
||||||
final startRefreshNative = moneroApi
|
final startRefreshNative =
|
||||||
.lookup<NativeFunction<start_refresh>>('start_refresh')
|
moneroApi.lookup<NativeFunction<start_refresh>>('start_refresh').asFunction<StartRefresh>();
|
||||||
.asFunction<StartRefresh>();
|
|
||||||
|
|
||||||
final connecToNodeNative = moneroApi
|
final connecToNodeNative = moneroApi
|
||||||
.lookup<NativeFunction<connect_to_node>>('connect_to_node')
|
.lookup<NativeFunction<connect_to_node>>('connect_to_node')
|
||||||
.asFunction<ConnectToNode>();
|
.asFunction<ConnectToNode>();
|
||||||
|
|
||||||
final setRefreshFromBlockHeightNative = moneroApi
|
final setRefreshFromBlockHeightNative = moneroApi
|
||||||
.lookup<NativeFunction<set_refresh_from_block_height>>(
|
.lookup<NativeFunction<set_refresh_from_block_height>>('set_refresh_from_block_height')
|
||||||
'set_refresh_from_block_height')
|
|
||||||
.asFunction<SetRefreshFromBlockHeight>();
|
.asFunction<SetRefreshFromBlockHeight>();
|
||||||
|
|
||||||
final setRecoveringFromSeedNative = moneroApi
|
final setRecoveringFromSeedNative = moneroApi
|
||||||
.lookup<NativeFunction<set_recovering_from_seed>>(
|
.lookup<NativeFunction<set_recovering_from_seed>>('set_recovering_from_seed')
|
||||||
'set_recovering_from_seed')
|
|
||||||
.asFunction<SetRecoveringFromSeed>();
|
.asFunction<SetRecoveringFromSeed>();
|
||||||
|
|
||||||
final storeNative =
|
final storeNative = moneroApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
|
||||||
moneroApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
|
|
||||||
|
|
||||||
final setPasswordNative =
|
final setPasswordNative =
|
||||||
moneroApi.lookup<NativeFunction<set_password>>('set_password').asFunction<SetPassword>();
|
moneroApi.lookup<NativeFunction<set_password>>('set_password').asFunction<SetPassword>();
|
||||||
|
|
||||||
final setListenerNative = moneroApi
|
final setListenerNative =
|
||||||
.lookup<NativeFunction<set_listener>>('set_listener')
|
moneroApi.lookup<NativeFunction<set_listener>>('set_listener').asFunction<SetListener>();
|
||||||
.asFunction<SetListener>();
|
|
||||||
|
|
||||||
final getSyncingHeightNative = moneroApi
|
final getSyncingHeightNative = moneroApi
|
||||||
.lookup<NativeFunction<get_syncing_height>>('get_syncing_height')
|
.lookup<NativeFunction<get_syncing_height>>('get_syncing_height')
|
||||||
|
@ -83,8 +74,7 @@ final isNeededToRefreshNative = moneroApi
|
||||||
.asFunction<IsNeededToRefresh>();
|
.asFunction<IsNeededToRefresh>();
|
||||||
|
|
||||||
final isNewTransactionExistNative = moneroApi
|
final isNewTransactionExistNative = moneroApi
|
||||||
.lookup<NativeFunction<is_new_transaction_exist>>(
|
.lookup<NativeFunction<is_new_transaction_exist>>('is_new_transaction_exist')
|
||||||
'is_new_transaction_exist')
|
|
||||||
.asFunction<IsNewTransactionExist>();
|
.asFunction<IsNewTransactionExist>();
|
||||||
|
|
||||||
final getSecretViewKeyNative = moneroApi
|
final getSecretViewKeyNative = moneroApi
|
||||||
|
@ -107,9 +97,8 @@ final closeCurrentWalletNative = moneroApi
|
||||||
.lookup<NativeFunction<close_current_wallet>>('close_current_wallet')
|
.lookup<NativeFunction<close_current_wallet>>('close_current_wallet')
|
||||||
.asFunction<CloseCurrentWallet>();
|
.asFunction<CloseCurrentWallet>();
|
||||||
|
|
||||||
final onStartupNative = moneroApi
|
final onStartupNative =
|
||||||
.lookup<NativeFunction<on_startup>>('on_startup')
|
moneroApi.lookup<NativeFunction<on_startup>>('on_startup').asFunction<OnStartup>();
|
||||||
.asFunction<OnStartup>();
|
|
||||||
|
|
||||||
final rescanBlockchainAsyncNative = moneroApi
|
final rescanBlockchainAsyncNative = moneroApi
|
||||||
.lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain')
|
.lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain')
|
||||||
|
@ -123,13 +112,19 @@ final setTrustedDaemonNative = moneroApi
|
||||||
.lookup<NativeFunction<set_trusted_daemon>>('set_trusted_daemon')
|
.lookup<NativeFunction<set_trusted_daemon>>('set_trusted_daemon')
|
||||||
.asFunction<SetTrustedDaemon>();
|
.asFunction<SetTrustedDaemon>();
|
||||||
|
|
||||||
final trustedDaemonNative = moneroApi
|
final trustedDaemonNative =
|
||||||
.lookup<NativeFunction<trusted_daemon>>('trusted_daemon')
|
moneroApi.lookup<NativeFunction<trusted_daemon>>('trusted_daemon').asFunction<TrustedDaemon>();
|
||||||
.asFunction<TrustedDaemon>();
|
|
||||||
|
|
||||||
final signMessageNative = moneroApi
|
final signMessageNative =
|
||||||
.lookup<NativeFunction<sign_message>>('sign_message')
|
moneroApi.lookup<NativeFunction<sign_message>>('sign_message').asFunction<SignMessage>();
|
||||||
.asFunction<SignMessage>();
|
|
||||||
|
final getCacheAttributeNative = moneroApi
|
||||||
|
.lookup<NativeFunction<get_cache_attribute>>('get_cache_attribute')
|
||||||
|
.asFunction<GetCacheAttribute>();
|
||||||
|
|
||||||
|
final setCacheAttributeNative = moneroApi
|
||||||
|
.lookup<NativeFunction<set_cache_attribute>>('set_cache_attribute')
|
||||||
|
.asFunction<SetCacheAttribute>();
|
||||||
|
|
||||||
int getSyncingHeight() => getSyncingHeightNative();
|
int getSyncingHeight() => getSyncingHeightNative();
|
||||||
|
|
||||||
|
@ -144,11 +139,9 @@ String getSeed() => convertUTF8ToString(pointer: getSeedNative());
|
||||||
String getAddress({int accountIndex = 0, int addressIndex = 0}) =>
|
String getAddress({int accountIndex = 0, int addressIndex = 0}) =>
|
||||||
convertUTF8ToString(pointer: getAddressNative(accountIndex, addressIndex));
|
convertUTF8ToString(pointer: getAddressNative(accountIndex, addressIndex));
|
||||||
|
|
||||||
int getFullBalance({int accountIndex = 0}) =>
|
int getFullBalance({int accountIndex = 0}) => getFullBalanceNative(accountIndex);
|
||||||
getFullBalanceNative(accountIndex);
|
|
||||||
|
|
||||||
int getUnlockedBalance({int accountIndex = 0}) =>
|
int getUnlockedBalance({int accountIndex = 0}) => getUnlockedBalanceNative(accountIndex);
|
||||||
getUnlockedBalanceNative(accountIndex);
|
|
||||||
|
|
||||||
int getCurrentHeight() => getCurrentHeightNative();
|
int getCurrentHeight() => getCurrentHeightNative();
|
||||||
|
|
||||||
|
@ -187,7 +180,7 @@ bool setupNodeSync(
|
||||||
passwordPointer,
|
passwordPointer,
|
||||||
_boolToInt(useSSL),
|
_boolToInt(useSSL),
|
||||||
_boolToInt(isLightWallet),
|
_boolToInt(isLightWallet),
|
||||||
socksProxyAddressPointer,
|
socksProxyAddressPointer,
|
||||||
errorMessagePointer) !=
|
errorMessagePointer) !=
|
||||||
0;
|
0;
|
||||||
|
|
||||||
|
@ -202,8 +195,7 @@ bool setupNodeSync(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSetupNode) {
|
if (!isSetupNode) {
|
||||||
throw SetupWalletException(
|
throw SetupWalletException(message: convertUTF8ToString(pointer: errorMessagePointer));
|
||||||
message: convertUTF8ToString(pointer: errorMessagePointer));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return isSetupNode;
|
return isSetupNode;
|
||||||
|
@ -213,8 +205,7 @@ void startRefreshSync() => startRefreshNative();
|
||||||
|
|
||||||
Future<bool> connectToNode() async => connecToNodeNative() != 0;
|
Future<bool> connectToNode() async => connecToNodeNative() != 0;
|
||||||
|
|
||||||
void setRefreshFromBlockHeight({required int height}) =>
|
void setRefreshFromBlockHeight({required int height}) => setRefreshFromBlockHeightNative(height);
|
||||||
setRefreshFromBlockHeightNative(height);
|
|
||||||
|
|
||||||
void setRecoveringFromSeed({required bool isRecovery}) =>
|
void setRecoveringFromSeed({required bool isRecovery}) =>
|
||||||
setRecoveringFromSeedNative(_boolToInt(isRecovery));
|
setRecoveringFromSeedNative(_boolToInt(isRecovery));
|
||||||
|
@ -230,7 +221,7 @@ void setPasswordSync(String password) {
|
||||||
final errorMessagePointer = calloc<Utf8Box>();
|
final errorMessagePointer = calloc<Utf8Box>();
|
||||||
final changed = setPasswordNative(passwordPointer, errorMessagePointer) != 0;
|
final changed = setPasswordNative(passwordPointer, errorMessagePointer) != 0;
|
||||||
calloc.free(passwordPointer);
|
calloc.free(passwordPointer);
|
||||||
|
|
||||||
if (!changed) {
|
if (!changed) {
|
||||||
final message = errorMessagePointer.ref.getValue();
|
final message = errorMessagePointer.ref.getValue();
|
||||||
calloc.free(errorMessagePointer);
|
calloc.free(errorMessagePointer);
|
||||||
|
@ -242,24 +233,19 @@ void setPasswordSync(String password) {
|
||||||
|
|
||||||
void closeCurrentWallet() => closeCurrentWalletNative();
|
void closeCurrentWallet() => closeCurrentWalletNative();
|
||||||
|
|
||||||
String getSecretViewKey() =>
|
String getSecretViewKey() => convertUTF8ToString(pointer: getSecretViewKeyNative());
|
||||||
convertUTF8ToString(pointer: getSecretViewKeyNative());
|
|
||||||
|
|
||||||
String getPublicViewKey() =>
|
String getPublicViewKey() => convertUTF8ToString(pointer: getPublicViewKeyNative());
|
||||||
convertUTF8ToString(pointer: getPublicViewKeyNative());
|
|
||||||
|
|
||||||
String getSecretSpendKey() =>
|
String getSecretSpendKey() => convertUTF8ToString(pointer: getSecretSpendKeyNative());
|
||||||
convertUTF8ToString(pointer: getSecretSpendKeyNative());
|
|
||||||
|
|
||||||
String getPublicSpendKey() =>
|
String getPublicSpendKey() => convertUTF8ToString(pointer: getPublicSpendKeyNative());
|
||||||
convertUTF8ToString(pointer: getPublicSpendKeyNative());
|
|
||||||
|
|
||||||
class SyncListener {
|
class SyncListener {
|
||||||
SyncListener(this.onNewBlock, this.onNewTransaction)
|
SyncListener(this.onNewBlock, this.onNewTransaction)
|
||||||
: _cachedBlockchainHeight = 0,
|
: _cachedBlockchainHeight = 0,
|
||||||
_lastKnownBlockHeight = 0,
|
_lastKnownBlockHeight = 0,
|
||||||
_initialSyncHeight = 0;
|
_initialSyncHeight = 0;
|
||||||
|
|
||||||
|
|
||||||
void Function(int, int, double) onNewBlock;
|
void Function(int, int, double) onNewBlock;
|
||||||
void Function() onNewTransaction;
|
void Function() onNewTransaction;
|
||||||
|
@ -281,8 +267,7 @@ class SyncListener {
|
||||||
_cachedBlockchainHeight = 0;
|
_cachedBlockchainHeight = 0;
|
||||||
_lastKnownBlockHeight = 0;
|
_lastKnownBlockHeight = 0;
|
||||||
_initialSyncHeight = 0;
|
_initialSyncHeight = 0;
|
||||||
_updateSyncInfoTimer ??=
|
_updateSyncInfoTimer ??= Timer.periodic(Duration(milliseconds: 1200), (_) async {
|
||||||
Timer.periodic(Duration(milliseconds: 1200), (_) async {
|
|
||||||
if (isNewTransactionExist()) {
|
if (isNewTransactionExist()) {
|
||||||
onNewTransaction();
|
onNewTransaction();
|
||||||
}
|
}
|
||||||
|
@ -321,8 +306,8 @@ class SyncListener {
|
||||||
void stop() => _updateSyncInfoTimer?.cancel();
|
void stop() => _updateSyncInfoTimer?.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
SyncListener setListeners(void Function(int, int, double) onNewBlock,
|
SyncListener setListeners(
|
||||||
void Function() onNewTransaction) {
|
void Function(int, int, double) onNewBlock, void Function() onNewTransaction) {
|
||||||
final listener = SyncListener(onNewBlock, onNewTransaction);
|
final listener = SyncListener(onNewBlock, onNewTransaction);
|
||||||
setListenerNative();
|
setListenerNative();
|
||||||
return listener;
|
return listener;
|
||||||
|
@ -364,7 +349,7 @@ Future<void> setupNode(
|
||||||
bool isLightWallet = false}) =>
|
bool isLightWallet = false}) =>
|
||||||
compute<Map<String, Object?>, void>(_setupNodeSync, {
|
compute<Map<String, Object?>, void>(_setupNodeSync, {
|
||||||
'address': address,
|
'address': address,
|
||||||
'login': login ,
|
'login': login,
|
||||||
'password': password,
|
'password': password,
|
||||||
'useSSL': useSSL,
|
'useSSL': useSSL,
|
||||||
'isLightWallet': isLightWallet,
|
'isLightWallet': isLightWallet,
|
||||||
|
@ -397,3 +382,23 @@ String signMessage(String message, {String address = ""}) {
|
||||||
|
|
||||||
return signature;
|
return signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool setCacheAttribute(String name, String value) {
|
||||||
|
final namePointer = name.toNativeUtf8();
|
||||||
|
final valuePointer = value.toNativeUtf8();
|
||||||
|
|
||||||
|
final isSet = setCacheAttributeNative(namePointer, valuePointer);
|
||||||
|
calloc.free(namePointer);
|
||||||
|
calloc.free(valuePointer);
|
||||||
|
|
||||||
|
return isSet == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getCacheAttribute(String name) {
|
||||||
|
final namePointer = name.toNativeUtf8();
|
||||||
|
|
||||||
|
final value = convertUTF8ToString(pointer: getCacheAttributeNative(namePointer));
|
||||||
|
calloc.free(namePointer);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
|
@ -149,10 +149,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
|
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.2"
|
version: "1.18.0"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -354,6 +354,30 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.8.0"
|
version: "4.8.0"
|
||||||
|
leak_tracker:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker
|
||||||
|
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.0.0"
|
||||||
|
leak_tracker_flutter_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_flutter_testing
|
||||||
|
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
|
leak_tracker_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_testing
|
||||||
|
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -366,26 +390,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.16"
|
version: "0.12.16+1"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "0.8.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.11.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -422,10 +446,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.3"
|
version: "1.9.0"
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -595,18 +619,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
stream_transform:
|
stream_transform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -635,10 +659,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.0"
|
version: "0.6.1"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -663,6 +687,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
|
vm_service:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vm_service
|
||||||
|
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "13.0.0"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: "direct overridden"
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
|
@ -671,14 +703,6 @@ 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: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.1.4-beta"
|
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -712,5 +736,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.1"
|
version: "3.1.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.1.0-185.0.dev <4.0.0"
|
dart: ">=3.2.0-0 <4.0.0"
|
||||||
flutter: ">=3.7.0"
|
flutter: ">=3.7.0"
|
||||||
|
|
|
@ -173,10 +173,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
|
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.1"
|
version: "1.18.0"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -399,6 +399,30 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.8.1"
|
version: "4.8.1"
|
||||||
|
leak_tracker:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker
|
||||||
|
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.0.0"
|
||||||
|
leak_tracker_flutter_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_flutter_testing
|
||||||
|
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
|
leak_tracker_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_testing
|
||||||
|
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
libcrypto:
|
libcrypto:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -419,26 +443,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
|
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.15"
|
version: "0.12.16+1"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "0.8.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.11.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -492,10 +516,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.3"
|
version: "1.9.0"
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -713,26 +737,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.10.0"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
stream_transform:
|
stream_transform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -761,10 +785,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
|
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1"
|
version: "0.6.1"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -789,8 +813,16 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
watcher:
|
vm_service:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vm_service
|
||||||
|
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "13.0.0"
|
||||||
|
watcher:
|
||||||
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
name: watcher
|
name: watcher
|
||||||
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
||||||
|
@ -830,5 +862,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.0.0 <4.0.0"
|
dart: ">=3.2.0-0 <4.0.0"
|
||||||
flutter: ">=3.7.0"
|
flutter: ">=3.7.0"
|
||||||
|
|
|
@ -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"
|
|
|
@ -19,30 +19,6 @@ class DefaultSPLTokens {
|
||||||
mint: 'usdcsol',
|
mint: 'usdcsol',
|
||||||
enabled: true,
|
enabled: true,
|
||||||
),
|
),
|
||||||
SPLToken(
|
|
||||||
name: 'Wrapped Ethereum (Sollet)',
|
|
||||||
symbol: 'soETH',
|
|
||||||
mintAddress: '2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk',
|
|
||||||
decimal: 6,
|
|
||||||
mint: 'soEth',
|
|
||||||
iconPath: 'assets/images/eth_icon.png',
|
|
||||||
),
|
|
||||||
SPLToken(
|
|
||||||
name: 'Wrapped SOL',
|
|
||||||
symbol: 'WSOL',
|
|
||||||
mintAddress: 'So11111111111111111111111111111111111111112',
|
|
||||||
decimal: 9,
|
|
||||||
mint: 'WSOL',
|
|
||||||
iconPath: 'assets/images/sol_icon.png',
|
|
||||||
),
|
|
||||||
SPLToken(
|
|
||||||
name: 'Wrapped Bitcoin (Sollet)',
|
|
||||||
symbol: 'BTC',
|
|
||||||
mintAddress: '9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E',
|
|
||||||
decimal: 6,
|
|
||||||
mint: 'btcsol',
|
|
||||||
iconPath: 'assets/images/btc.png',
|
|
||||||
),
|
|
||||||
SPLToken(
|
SPLToken(
|
||||||
name: 'Bonk',
|
name: 'Bonk',
|
||||||
symbol: 'Bonk',
|
symbol: 'Bonk',
|
||||||
|
@ -50,21 +26,7 @@ class DefaultSPLTokens {
|
||||||
decimal: 5,
|
decimal: 5,
|
||||||
mint: 'Bonk',
|
mint: 'Bonk',
|
||||||
iconPath: 'assets/images/bonk_icon.png',
|
iconPath: 'assets/images/bonk_icon.png',
|
||||||
),
|
enabled: true,
|
||||||
SPLToken(
|
|
||||||
name: 'Helium Network Token',
|
|
||||||
symbol: 'HNT',
|
|
||||||
mintAddress: 'hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux',
|
|
||||||
decimal: 8,
|
|
||||||
mint: 'hnt',
|
|
||||||
iconPath: 'assets/images/hnt_icon.png',
|
|
||||||
),
|
|
||||||
SPLToken(
|
|
||||||
name: 'Pyth Network',
|
|
||||||
symbol: 'PYTH',
|
|
||||||
mintAddress: 'HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3',
|
|
||||||
decimal: 6,
|
|
||||||
mint: 'pyth',
|
|
||||||
),
|
),
|
||||||
SPLToken(
|
SPLToken(
|
||||||
name: 'Raydium',
|
name: 'Raydium',
|
||||||
|
@ -73,6 +35,51 @@ class DefaultSPLTokens {
|
||||||
decimal: 6,
|
decimal: 6,
|
||||||
mint: 'ray',
|
mint: 'ray',
|
||||||
iconPath: 'assets/images/ray_icon.png',
|
iconPath: 'assets/images/ray_icon.png',
|
||||||
|
enabled: true,
|
||||||
|
),
|
||||||
|
SPLToken(
|
||||||
|
name: 'Wrapped Ethereum (Sollet)',
|
||||||
|
symbol: 'soETH',
|
||||||
|
mintAddress: '2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk',
|
||||||
|
decimal: 6,
|
||||||
|
mint: 'soEth',
|
||||||
|
iconPath: 'assets/images/eth_icon.png',
|
||||||
|
enabled: false,
|
||||||
|
),
|
||||||
|
SPLToken(
|
||||||
|
name: 'Wrapped SOL',
|
||||||
|
symbol: 'WSOL',
|
||||||
|
mintAddress: 'So11111111111111111111111111111111111111112',
|
||||||
|
decimal: 9,
|
||||||
|
mint: 'WSOL',
|
||||||
|
iconPath: 'assets/images/sol_icon.png',
|
||||||
|
enabled: false,
|
||||||
|
),
|
||||||
|
SPLToken(
|
||||||
|
name: 'Wrapped Bitcoin (Sollet)',
|
||||||
|
symbol: 'BTC',
|
||||||
|
mintAddress: '9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E',
|
||||||
|
decimal: 6,
|
||||||
|
mint: 'btcsol',
|
||||||
|
iconPath: 'assets/images/btc.png',
|
||||||
|
enabled: false,
|
||||||
|
),
|
||||||
|
SPLToken(
|
||||||
|
name: 'Helium Network Token',
|
||||||
|
symbol: 'HNT',
|
||||||
|
mintAddress: 'hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux',
|
||||||
|
decimal: 8,
|
||||||
|
mint: 'hnt',
|
||||||
|
iconPath: 'assets/images/hnt_icon.png',
|
||||||
|
enabled: false,
|
||||||
|
),
|
||||||
|
SPLToken(
|
||||||
|
name: 'Pyth Network',
|
||||||
|
symbol: 'PYTH',
|
||||||
|
mintAddress: 'HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3',
|
||||||
|
decimal: 6,
|
||||||
|
mint: 'pyth',
|
||||||
|
enabled: false,
|
||||||
),
|
),
|
||||||
SPLToken(
|
SPLToken(
|
||||||
name: 'GMT',
|
name: 'GMT',
|
||||||
|
@ -81,6 +88,7 @@ class DefaultSPLTokens {
|
||||||
decimal: 6,
|
decimal: 6,
|
||||||
mint: 'ray',
|
mint: 'ray',
|
||||||
iconPath: 'assets/images/gmt_icon.png',
|
iconPath: 'assets/images/gmt_icon.png',
|
||||||
|
enabled: false,
|
||||||
),
|
),
|
||||||
SPLToken(
|
SPLToken(
|
||||||
name: 'AvocadoCoin',
|
name: 'AvocadoCoin',
|
||||||
|
@ -89,6 +97,7 @@ class DefaultSPLTokens {
|
||||||
decimal: 8,
|
decimal: 8,
|
||||||
mint: 'avdo',
|
mint: 'avdo',
|
||||||
iconPath: 'assets/images/avdo_icon.png',
|
iconPath: 'assets/images/avdo_icon.png',
|
||||||
|
enabled: false,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ class SolanaBalance extends Balance {
|
||||||
|
|
||||||
String _balanceFormatted() {
|
String _balanceFormatted() {
|
||||||
String stringBalance = balance.toString();
|
String stringBalance = balance.toString();
|
||||||
if (stringBalance.toString().length >= 6) {
|
if (stringBalance.toString().length >= 12) {
|
||||||
stringBalance = stringBalance.substring(0, 6);
|
stringBalance = stringBalance.substring(0, 12);
|
||||||
}
|
}
|
||||||
return stringBalance;
|
return stringBalance;
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,11 +130,6 @@ class TronClient {
|
||||||
final energyInSun = chainParams.getEnergyFee!;
|
final energyInSun = chainParams.getEnergyFee!;
|
||||||
log('Energy In Sun: $energyInSun');
|
log('Energy In Sun: $energyInSun');
|
||||||
|
|
||||||
log(
|
|
||||||
'Create Account Fee In System Contract for Chain: ${chainParams.getCreateNewAccountFeeInSystemContract!}',
|
|
||||||
);
|
|
||||||
log('Create Account Fee for Chain: ${chainParams.getCreateAccountFee}');
|
|
||||||
|
|
||||||
final fakeTransaction = Transaction(
|
final fakeTransaction = Transaction(
|
||||||
rawData: rawTransaction,
|
rawData: rawTransaction,
|
||||||
signature: [Uint8List(65)],
|
signature: [Uint8List(65)],
|
||||||
|
@ -185,17 +180,6 @@ class TronClient {
|
||||||
totalBurn += chainParams.getMemoFee!;
|
totalBurn += chainParams.getMemoFee!;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if receiver's account is active
|
|
||||||
final receiverAccountInfo =
|
|
||||||
await _provider!.request(TronRequestGetAccount(address: receiverAddress));
|
|
||||||
|
|
||||||
/// Calculate the resources required to create a new account.
|
|
||||||
if (receiverAccountInfo == null) {
|
|
||||||
totalBurn += chainParams.getCreateNewAccountFeeInSystemContract!;
|
|
||||||
|
|
||||||
totalBurn += (chainParams.getCreateAccountFee! * bandWidthInSun);
|
|
||||||
}
|
|
||||||
|
|
||||||
log('Final total burn: $totalBurn');
|
log('Final total burn: $totalBurn');
|
||||||
|
|
||||||
return totalBurn;
|
return totalBurn;
|
||||||
|
@ -224,7 +208,7 @@ class TronClient {
|
||||||
TransactionContract(type: contract.contractType, parameter: parameter);
|
TransactionContract(type: contract.contractType, parameter: parameter);
|
||||||
|
|
||||||
// Set the transaction expiration time (maximum 24 hours)
|
// Set the transaction expiration time (maximum 24 hours)
|
||||||
final expireTime = DateTime.now().toUtc().add(const Duration(hours: 24));
|
final expireTime = DateTime.now().add(const Duration(minutes: 30));
|
||||||
|
|
||||||
// Create a raw transaction
|
// Create a raw transaction
|
||||||
TransactionRaw rawTransaction = TransactionRaw(
|
TransactionRaw rawTransaction = TransactionRaw(
|
||||||
|
@ -385,7 +369,7 @@ class TronClient {
|
||||||
TransactionContract(type: contract.contractType, parameter: parameter);
|
TransactionContract(type: contract.contractType, parameter: parameter);
|
||||||
|
|
||||||
// Set the transaction expiration time (maximum 24 hours)
|
// Set the transaction expiration time (maximum 24 hours)
|
||||||
final expireTime = DateTime.now().toUtc().add(const Duration(hours: 24));
|
final expireTime = DateTime.now().add(const Duration(minutes: 30));
|
||||||
|
|
||||||
// Create a raw transaction
|
// Create a raw transaction
|
||||||
TransactionRaw rawTransaction = TransactionRaw(
|
TransactionRaw rawTransaction = TransactionRaw(
|
||||||
|
@ -403,7 +387,7 @@ class TronClient {
|
||||||
if (feeLimit > tronBalanceInt) {
|
if (feeLimit > tronBalanceInt) {
|
||||||
final feeInTrx = TronHelper.fromSun(BigInt.parse(feeLimit.toString()));
|
final feeInTrx = TronHelper.fromSun(BigInt.parse(feeLimit.toString()));
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'You don\'t have enough TRX to cover the transaction fee for this transaction. Kindly top up.\nTransaction fee: $feeInTrx TRX',
|
'You don\'t have enough TRX to cover the transaction fee for this transaction. Please top up.\nTransaction fee: $feeInTrx TRX',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,7 +444,7 @@ class TronClient {
|
||||||
if (feeLimit > tronBalanceInt) {
|
if (feeLimit > tronBalanceInt) {
|
||||||
final feeInTrx = TronHelper.fromSun(BigInt.parse(feeLimit.toString()));
|
final feeInTrx = TronHelper.fromSun(BigInt.parse(feeLimit.toString()));
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'You don\'t have enough TRX to cover the transaction fee for this transaction. Kindly top up. Transaction fee: $feeInTrx TRX',
|
'You don\'t have enough TRX to cover the transaction fee for this transaction. Please top up. Transaction fee: $feeInTrx TRX',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,12 +307,13 @@ 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
|
||||||
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
||||||
UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841
|
UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841
|
||||||
url_launcher_ios: 6116280ddcfe98ab8820085d8d76ae7449447586
|
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||||
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
|
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
|
||||||
workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
|
workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -371,6 +369,9 @@ class CWBitcoin extends Bitcoin {
|
||||||
case "p2wpkh-p2sh":
|
case "p2wpkh-p2sh":
|
||||||
address = generateP2SHAddress(hd: hd, network: network);
|
address = generateP2SHAddress(hd: hd, network: network);
|
||||||
break;
|
break;
|
||||||
|
case "p2tr":
|
||||||
|
address = generateP2TRAddress(hd: hd, network: network);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -462,4 +463,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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -281,17 +281,19 @@ class MoonPayProvider extends BuyProvider {
|
||||||
throw Exception('Could not launch URL');
|
throw Exception('Could not launch URL');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await showDialog<void>(
|
if (context.mounted) {
|
||||||
context: context,
|
await showDialog<void>(
|
||||||
builder: (BuildContext context) {
|
context: context,
|
||||||
return AlertWithOneAction(
|
builder: (BuildContext context) {
|
||||||
alertTitle: 'MoonPay',
|
return AlertWithOneAction(
|
||||||
alertContent: 'The MoonPay service is currently unavailable: $e',
|
alertTitle: 'MoonPay',
|
||||||
buttonText: S.of(context).ok,
|
alertContent: 'The MoonPay service is currently unavailable: $e',
|
||||||
buttonAction: () => Navigator.of(context).pop(),
|
buttonText: S.of(context).ok,
|
||||||
);
|
buttonAction: () => Navigator.of(context).pop(),
|
||||||
},
|
);
|
||||||
);
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,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.nano:
|
case CryptoCurrency.nano:
|
||||||
return '[0-9a-zA-Z_]';
|
return '[0-9a-zA-Z_]';
|
||||||
case CryptoCurrency.banano:
|
case CryptoCurrency.banano:
|
||||||
|
@ -274,7 +274,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 '';
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ class WalletCreationService {
|
||||||
checkIfExists(credentials.name);
|
checkIfExists(credentials.name);
|
||||||
final password = generateWalletPassword();
|
final password = generateWalletPassword();
|
||||||
credentials.password = password;
|
credentials.password = password;
|
||||||
if (type == WalletType.bitcoinCash || type == WalletType.ethereum) {
|
if (_hasSeedPhraseLengthOption) {
|
||||||
credentials.seedPhraseLength = settingsStore.seedPhraseLength.value;
|
credentials.seedPhraseLength = settingsStore.seedPhraseLength.value;
|
||||||
}
|
}
|
||||||
await keyService.saveWalletPassword(password: password, walletName: credentials.name);
|
await keyService.saveWalletPassword(password: password, walletName: credentials.name);
|
||||||
|
@ -72,6 +72,25 @@ class WalletCreationService {
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get _hasSeedPhraseLengthOption {
|
||||||
|
switch (type) {
|
||||||
|
case WalletType.ethereum:
|
||||||
|
case WalletType.bitcoinCash:
|
||||||
|
case WalletType.polygon:
|
||||||
|
case WalletType.solana:
|
||||||
|
case WalletType.tron:
|
||||||
|
return true;
|
||||||
|
case WalletType.monero:
|
||||||
|
case WalletType.none:
|
||||||
|
case WalletType.bitcoin:
|
||||||
|
case WalletType.litecoin:
|
||||||
|
case WalletType.haven:
|
||||||
|
case WalletType.nano:
|
||||||
|
case WalletType.banano:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<WalletBase> restoreFromKeys(WalletCredentials credentials, {bool? isTestnet}) async {
|
Future<WalletBase> restoreFromKeys(WalletCredentials credentials, {bool? isTestnet}) async {
|
||||||
checkIfExists(credentials.name);
|
checkIfExists(credentials.name);
|
||||||
final password = generateWalletPassword();
|
final password = generateWalletPassword();
|
||||||
|
|
93
lib/di.dart
93
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';
|
||||||
|
@ -14,6 +15,8 @@ import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
||||||
import 'package:cake_wallet/core/auth_service.dart';
|
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/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';
|
||||||
|
@ -26,10 +29,6 @@ import 'package:cake_wallet/entities/contact.dart';
|
||||||
import 'package:cake_wallet/entities/contact_record.dart';
|
import 'package:cake_wallet/entities/contact_record.dart';
|
||||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
|
||||||
import 'package:cake_wallet/tron/tron.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
|
|
||||||
import 'package:cw_core/receive_page_option.dart';
|
|
||||||
import 'package:cake_wallet/entities/qr_view_data.dart';
|
import 'package:cake_wallet/entities/qr_view_data.dart';
|
||||||
import 'package:cake_wallet/entities/template.dart';
|
import 'package:cake_wallet/entities/template.dart';
|
||||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||||
|
@ -105,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';
|
||||||
|
@ -148,6 +149,7 @@ import 'package:cake_wallet/store/templates/send_template_store.dart';
|
||||||
import 'package:cake_wallet/store/wallet_list_store.dart';
|
import 'package:cake_wallet/store/wallet_list_store.dart';
|
||||||
import 'package:cake_wallet/store/yat/yat_store.dart';
|
import 'package:cake_wallet/store/yat/yat_store.dart';
|
||||||
import 'package:cake_wallet/themes/theme_list.dart';
|
import 'package:cake_wallet/themes/theme_list.dart';
|
||||||
|
import 'package:cake_wallet/tron/tron.dart';
|
||||||
import 'package:cake_wallet/utils/device_info.dart';
|
import 'package:cake_wallet/utils/device_info.dart';
|
||||||
import 'package:cake_wallet/utils/payment_request.dart';
|
import 'package:cake_wallet/utils/payment_request.dart';
|
||||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
|
@ -161,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';
|
||||||
|
@ -180,6 +182,7 @@ import 'package:cake_wallet/view_model/ionia/ionia_gift_card_details_view_model.
|
||||||
import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
|
import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/ionia/ionia_payment_status_view_model.dart';
|
import 'package:cake_wallet/view_model/ionia/ionia_payment_status_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart';
|
import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
||||||
import 'package:cake_wallet/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart';
|
import 'package:cake_wallet/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart';
|
import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart';
|
||||||
|
@ -200,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';
|
||||||
|
@ -231,41 +235,10 @@ import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
||||||
import 'package:get_it/get_it.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
import 'package:hive/hive.dart';
|
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 'package:cake_wallet/core/secure_storage.dart';
|
|
||||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
|
||||||
import 'package:cw_core/wallet_type.dart';
|
|
||||||
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
|
|
||||||
import 'package:cake_wallet/store/authentication_store.dart';
|
|
||||||
import 'package:cake_wallet/store/dashboard/trades_store.dart';
|
|
||||||
import 'package:cake_wallet/store/dashboard/trade_filter_store.dart';
|
|
||||||
import 'package:cake_wallet/store/dashboard/transaction_filter_store.dart';
|
|
||||||
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
|
||||||
import 'package:cake_wallet/store/templates/send_template_store.dart';
|
|
||||||
import 'package:cake_wallet/store/templates/exchange_template_store.dart';
|
|
||||||
import 'package:cake_wallet/entities/template.dart';
|
|
||||||
import 'package:cake_wallet/exchange/exchange_template.dart';
|
|
||||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
|
||||||
import 'package:cake_wallet/src/screens/dashboard/pages/address_page.dart';
|
|
||||||
import 'package:cake_wallet/anypay/anypay_api.dart';
|
|
||||||
import 'package:cake_wallet/view_model/ionia/ionia_gift_card_details_view_model.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.dart';
|
|
||||||
import 'package:cake_wallet/view_model/ionia/ionia_payment_status_view_model.dart';
|
|
||||||
import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
|
|
||||||
import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart';
|
|
||||||
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
|
||||||
import 'package:cake_wallet/entities/qr_view_data.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;
|
||||||
|
|
||||||
|
@ -339,7 +312,6 @@ Future<void> setup({
|
||||||
getIt.registerFactory<Box<Node>>(() => _powNodeSource, instanceName: Node.boxName + "pow");
|
getIt.registerFactory<Box<Node>>(() => _powNodeSource, instanceName: Node.boxName + "pow");
|
||||||
|
|
||||||
getIt.registerSingleton(AuthenticationStore());
|
getIt.registerSingleton(AuthenticationStore());
|
||||||
getIt.registerSingleton(LedgerViewModel());
|
|
||||||
getIt.registerSingleton<WalletListStore>(WalletListStore());
|
getIt.registerSingleton<WalletListStore>(WalletListStore());
|
||||||
getIt.registerSingleton(NodeListStoreBase.instance);
|
getIt.registerSingleton(NodeListStoreBase.instance);
|
||||||
getIt.registerSingleton<SettingsStore>(settingsStore);
|
getIt.registerSingleton<SettingsStore>(settingsStore);
|
||||||
|
@ -359,11 +331,12 @@ Future<void> setup({
|
||||||
getIt.registerSingleton<ExchangeTemplateStore>(
|
getIt.registerSingleton<ExchangeTemplateStore>(
|
||||||
ExchangeTemplateStore(templateSource: _exchangeTemplates));
|
ExchangeTemplateStore(templateSource: _exchangeTemplates));
|
||||||
getIt.registerSingleton<YatStore>(
|
getIt.registerSingleton<YatStore>(
|
||||||
YatStore(appStore: getIt.get<AppStore>(), secureStorage: getIt.get<SecureStorage>())
|
YatStore(appStore: getIt.get<AppStore>(), secureStorage: getIt.get<SecureStorage>())..init());
|
||||||
..init());
|
|
||||||
getIt.registerSingleton<AnonpayTransactionsStore>(
|
getIt.registerSingleton<AnonpayTransactionsStore>(
|
||||||
AnonpayTransactionsStore(anonpayInvoiceInfoSource: _anonpayInvoiceInfoSource));
|
AnonpayTransactionsStore(anonpayInvoiceInfoSource: _anonpayInvoiceInfoSource));
|
||||||
|
|
||||||
|
getIt.registerLazySingleton(() => LedgerViewModel());
|
||||||
|
|
||||||
final secretStore = await SecretStoreBase.load(getIt.get<SecureStorage>());
|
final secretStore = await SecretStoreBase.load(getIt.get<SecureStorage>());
|
||||||
|
|
||||||
getIt.registerSingleton<SecretStore>(secretStore);
|
getIt.registerSingleton<SecretStore>(secretStore);
|
||||||
|
@ -600,7 +573,7 @@ Future<void> setup({
|
||||||
getIt.registerFactory<Modify2FAPage>(
|
getIt.registerFactory<Modify2FAPage>(
|
||||||
() => Modify2FAPage(setup2FAViewModel: getIt.get<Setup2FAViewModel>()));
|
() => Modify2FAPage(setup2FAViewModel: getIt.get<Setup2FAViewModel>()));
|
||||||
|
|
||||||
getIt.registerFactory<DesktopSettingsPage>(() => DesktopSettingsPage());
|
getIt.registerFactory<DesktopSettingsPage>(() => DesktopSettingsPage(getIt.get<DashboardViewModel>()));
|
||||||
|
|
||||||
getIt.registerFactoryParam<ReceiveOptionViewModel, ReceivePageOption?, void>(
|
getIt.registerFactoryParam<ReceiveOptionViewModel, ReceivePageOption?, void>(
|
||||||
(pageOption, _) => ReceiveOptionViewModel(getIt.get<AppStore>().wallet!, pageOption));
|
(pageOption, _) => ReceiveOptionViewModel(getIt.get<AppStore>().wallet!, pageOption));
|
||||||
|
@ -655,7 +628,7 @@ Future<void> setup({
|
||||||
getIt.get<BalanceViewModel>(),
|
getIt.get<BalanceViewModel>(),
|
||||||
getIt.get<ContactListViewModel>(),
|
getIt.get<ContactListViewModel>(),
|
||||||
_transactionDescriptionBox,
|
_transactionDescriptionBox,
|
||||||
getIt.get<LedgerViewModel>(),
|
getIt.get<AppStore>().wallet!.isHardwareWallet ? getIt.get<LedgerViewModel>() : null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -775,6 +748,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!);
|
||||||
});
|
});
|
||||||
|
@ -825,8 +801,8 @@ Future<void> setup({
|
||||||
|
|
||||||
getIt.registerFactory(() => ConnectionSyncPage(getIt.get<DashboardViewModel>()));
|
getIt.registerFactory(() => ConnectionSyncPage(getIt.get<DashboardViewModel>()));
|
||||||
|
|
||||||
getIt.registerFactory(
|
getIt.registerFactory(() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(),
|
||||||
() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(), getIt.get<AuthService>()));
|
getIt.get<AuthService>(), getIt.get<AppStore>().wallet!.isHardwareWallet));
|
||||||
|
|
||||||
getIt.registerFactory(() => PrivacyPage(getIt.get<PrivacySettingsViewModel>()));
|
getIt.registerFactory(() => PrivacyPage(getIt.get<PrivacySettingsViewModel>()));
|
||||||
|
|
||||||
|
@ -836,6 +812,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(
|
||||||
|
@ -862,10 +841,14 @@ Future<void> setup({
|
||||||
isSelected: isSelected));
|
isSelected: isSelected));
|
||||||
|
|
||||||
getIt.registerFactory<RobinhoodBuyProvider>(() => RobinhoodBuyProvider(
|
getIt.registerFactory<RobinhoodBuyProvider>(() => RobinhoodBuyProvider(
|
||||||
wallet: getIt.get<AppStore>().wallet!, ledgerVM: getIt.get<LedgerViewModel>()));
|
wallet: getIt.get<AppStore>().wallet!,
|
||||||
|
ledgerVM:
|
||||||
|
getIt.get<AppStore>().wallet!.isHardwareWallet ? getIt.get<LedgerViewModel>() : null));
|
||||||
|
|
||||||
getIt.registerFactory<DFXBuyProvider>(() => DFXBuyProvider(
|
getIt.registerFactory<DFXBuyProvider>(() => DFXBuyProvider(
|
||||||
wallet: getIt.get<AppStore>().wallet!, ledgerVM: getIt.get<LedgerViewModel>()));
|
wallet: getIt.get<AppStore>().wallet!,
|
||||||
|
ledgerVM:
|
||||||
|
getIt.get<AppStore>().wallet!.isHardwareWallet ? getIt.get<LedgerViewModel>() : null));
|
||||||
|
|
||||||
getIt.registerFactory<MoonPayProvider>(() => MoonPayProvider(
|
getIt.registerFactory<MoonPayProvider>(() => MoonPayProvider(
|
||||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||||
|
@ -919,7 +902,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:
|
||||||
|
@ -966,9 +953,9 @@ Future<void> setup({
|
||||||
(derivations, _) => WalletRestoreChooseDerivationViewModel(derivationInfos: derivations));
|
(derivations, _) => WalletRestoreChooseDerivationViewModel(derivationInfos: derivations));
|
||||||
|
|
||||||
getIt.registerFactoryParam<WalletRestoreChooseDerivationPage, List<DerivationInfo>, void>(
|
getIt.registerFactoryParam<WalletRestoreChooseDerivationPage, List<DerivationInfo>, void>(
|
||||||
(credentials, _) =>
|
(derivations, _) =>
|
||||||
WalletRestoreChooseDerivationPage(getIt.get<WalletRestoreChooseDerivationViewModel>(
|
WalletRestoreChooseDerivationPage(getIt.get<WalletRestoreChooseDerivationViewModel>(
|
||||||
param1: credentials,
|
param1: derivations,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
getIt.registerFactoryParam<TransactionDetailsViewModel, TransactionInfo, void>(
|
getIt.registerFactoryParam<TransactionDetailsViewModel, TransactionInfo, void>(
|
||||||
|
@ -1017,8 +1004,8 @@ Future<void> setup({
|
||||||
|
|
||||||
getIt.registerFactory(() => BackupPage(getIt.get<BackupViewModel>()));
|
getIt.registerFactory(() => BackupPage(getIt.get<BackupViewModel>()));
|
||||||
|
|
||||||
getIt.registerFactory(() =>
|
getIt.registerFactory(
|
||||||
EditBackupPasswordViewModel(getIt.get<SecureStorage>(), getIt.get<SecretStore>()));
|
() => EditBackupPasswordViewModel(getIt.get<SecureStorage>(), getIt.get<SecretStore>()));
|
||||||
|
|
||||||
getIt.registerFactory(() => EditBackupPasswordPage(getIt.get<EditBackupPasswordViewModel>()));
|
getIt.registerFactory(() => EditBackupPasswordPage(getIt.get<EditBackupPasswordViewModel>()));
|
||||||
|
|
||||||
|
@ -1066,8 +1053,8 @@ Future<void> setup({
|
||||||
|
|
||||||
getIt.registerFactory(() => SupportPage(getIt.get<SupportViewModel>()));
|
getIt.registerFactory(() => SupportPage(getIt.get<SupportViewModel>()));
|
||||||
|
|
||||||
getIt.registerFactory(() => SupportChatPage(getIt.get<SupportViewModel>(),
|
getIt.registerFactory(() =>
|
||||||
secureStorage: getIt.get<SecureStorage>()));
|
SupportChatPage(getIt.get<SupportViewModel>(), secureStorage: getIt.get<SecureStorage>()));
|
||||||
|
|
||||||
getIt.registerFactory(() => SupportOtherLinksPage(getIt.get<SupportViewModel>()));
|
getIt.registerFactory(() => SupportOtherLinksPage(getIt.get<SupportViewModel>()));
|
||||||
|
|
||||||
|
@ -1116,7 +1103,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';
|
||||||
|
@ -65,6 +67,7 @@ class PreferencesKey {
|
||||||
static const lookupsUnstoppableDomains = 'looks_up_unstoppable_domain';
|
static const lookupsUnstoppableDomains = 'looks_up_unstoppable_domain';
|
||||||
static const lookupsOpenAlias = 'looks_up_open_alias';
|
static const lookupsOpenAlias = 'looks_up_open_alias';
|
||||||
static const lookupsENS = 'looks_up_ens';
|
static const lookupsENS = 'looks_up_ens';
|
||||||
|
static const showCameraConsent = 'show_camera_consent';
|
||||||
|
|
||||||
static String moneroWalletUpdateV1Key(String name) =>
|
static String moneroWalletUpdateV1Key(String name) =>
|
||||||
'${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';
|
'${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';
|
||||||
|
|
|
@ -22,10 +22,11 @@ class ExchangeProviderDescription extends EnumerableItem<int> with Serializable<
|
||||||
ExchangeProviderDescription(title: 'Trocador', raw: 5, image: 'assets/images/trocador.png');
|
ExchangeProviderDescription(title: 'Trocador', raw: 5, image: 'assets/images/trocador.png');
|
||||||
static const exolix =
|
static const exolix =
|
||||||
ExchangeProviderDescription(title: 'Exolix', raw: 6, image: 'assets/images/exolix.png');
|
ExchangeProviderDescription(title: 'Exolix', raw: 6, image: 'assets/images/exolix.png');
|
||||||
static const thorChain =
|
|
||||||
ExchangeProviderDescription(title: 'ThorChain' , raw: 8, image: 'assets/images/thorchain.png');
|
|
||||||
|
|
||||||
static const all = ExchangeProviderDescription(title: 'All trades', raw: 7, image: '');
|
static const all = ExchangeProviderDescription(title: 'All trades', raw: 7, image: '');
|
||||||
|
static const thorChain =
|
||||||
|
ExchangeProviderDescription(title: 'ThorChain', raw: 8, image: 'assets/images/thorchain.png');
|
||||||
|
static const quantex =
|
||||||
|
ExchangeProviderDescription(title: 'Quantex', raw: 9, image: 'assets/images/quantex.png');
|
||||||
|
|
||||||
static ExchangeProviderDescription deserialize({required int raw}) {
|
static ExchangeProviderDescription deserialize({required int raw}) {
|
||||||
switch (raw) {
|
switch (raw) {
|
||||||
|
@ -43,10 +44,12 @@ class ExchangeProviderDescription extends EnumerableItem<int> with Serializable<
|
||||||
return trocador;
|
return trocador;
|
||||||
case 6:
|
case 6:
|
||||||
return exolix;
|
return exolix;
|
||||||
case 8:
|
|
||||||
return thorChain;
|
|
||||||
case 7:
|
case 7:
|
||||||
return all;
|
return all;
|
||||||
|
case 8:
|
||||||
|
return thorChain;
|
||||||
|
case 9:
|
||||||
|
return quantex;
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected token: $raw for ExchangeProviderDescription deserialize');
|
throw Exception('Unexpected token: $raw for ExchangeProviderDescription deserialize');
|
||||||
}
|
}
|
||||||
|
|
252
lib/exchange/provider/quantex_exchange_provider.dart
Normal file
252
lib/exchange/provider/quantex_exchange_provider.dart
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||||
|
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||||
|
import 'package:cake_wallet/exchange/limits.dart';
|
||||||
|
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
|
||||||
|
import 'package:cake_wallet/exchange/trade.dart';
|
||||||
|
import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
|
||||||
|
import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
|
||||||
|
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||||
|
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||||
|
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:http/http.dart';
|
||||||
|
|
||||||
|
class QuantexExchangeProvider extends ExchangeProvider {
|
||||||
|
QuantexExchangeProvider() : super(pairList: supportedPairs(_notSupported));
|
||||||
|
|
||||||
|
static final List<CryptoCurrency> _notSupported = [
|
||||||
|
...(CryptoCurrency.all
|
||||||
|
.where((element) => ![
|
||||||
|
CryptoCurrency.btc,
|
||||||
|
CryptoCurrency.sol,
|
||||||
|
CryptoCurrency.eth,
|
||||||
|
CryptoCurrency.ltc,
|
||||||
|
CryptoCurrency.ada,
|
||||||
|
CryptoCurrency.bch,
|
||||||
|
CryptoCurrency.usdt,
|
||||||
|
CryptoCurrency.bnb,
|
||||||
|
CryptoCurrency.xmr,
|
||||||
|
].contains(element))
|
||||||
|
.toList())
|
||||||
|
];
|
||||||
|
|
||||||
|
static final markup = secrets.quantexExchangeMarkup;
|
||||||
|
|
||||||
|
static const apiAuthority = 'api.myquantex.com';
|
||||||
|
static const getRate = '/api/swap/get-rate';
|
||||||
|
static const getCoins = '/api/swap/get-coins';
|
||||||
|
static const createOrder = '/api/swap/create-order';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => 'Quantex';
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isAvailable => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isEnabled => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get supportsFixedRate => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ExchangeProviderDescription get description => ExchangeProviderDescription.quantex;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> checkIsAvailable() async => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Limits> fetchLimits({
|
||||||
|
required CryptoCurrency from,
|
||||||
|
required CryptoCurrency to,
|
||||||
|
required bool isFixedRateMode,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
final uri = Uri.https(apiAuthority, getCoins);
|
||||||
|
final response = await get(uri);
|
||||||
|
|
||||||
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
|
||||||
|
if (response.statusCode != 200)
|
||||||
|
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||||
|
|
||||||
|
final coinsInfo = responseJSON['data'] as List<dynamic>;
|
||||||
|
|
||||||
|
for (var coin in coinsInfo) {
|
||||||
|
if (coin['id'].toString().toUpperCase() == _normalizeCurrency(from)) {
|
||||||
|
return Limits(
|
||||||
|
min: double.parse(coin['min'].toString()),
|
||||||
|
max: double.parse(coin['max'].toString()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// coin not found:
|
||||||
|
return Limits(min: 0, max: 0);
|
||||||
|
} catch (e) {
|
||||||
|
print(e.toString());
|
||||||
|
return Limits(min: 0, max: 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<double> fetchRate({
|
||||||
|
required CryptoCurrency from,
|
||||||
|
required CryptoCurrency to,
|
||||||
|
required double amount,
|
||||||
|
required bool isFixedRateMode,
|
||||||
|
required bool isReceiveAmount,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
if (amount == 0) return 0.0;
|
||||||
|
|
||||||
|
final headers = <String, String>{};
|
||||||
|
final params = <String, dynamic>{};
|
||||||
|
final body = <String, String>{
|
||||||
|
'coin_send': _normalizeCurrency(from),
|
||||||
|
'coin_receive': _normalizeCurrency(to),
|
||||||
|
'ref': 'cake',
|
||||||
|
};
|
||||||
|
|
||||||
|
final uri = Uri.https(apiAuthority, getRate, params);
|
||||||
|
final response = await post(uri, body: body, headers: headers);
|
||||||
|
final responseBody = json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
|
||||||
|
if (response.statusCode != 200)
|
||||||
|
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||||
|
|
||||||
|
final data = responseBody['data'] as Map<String, dynamic>;
|
||||||
|
double rate = double.parse(data['price'].toString());
|
||||||
|
return rate;
|
||||||
|
} catch (e) {
|
||||||
|
print("error fetching rate: ${e.toString()}");
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Trade> createTrade({
|
||||||
|
required TradeRequest request,
|
||||||
|
required bool isFixedRateMode,
|
||||||
|
required bool isSendAll,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
final headers = <String, String>{};
|
||||||
|
final params = <String, dynamic>{};
|
||||||
|
var body = <String, dynamic>{
|
||||||
|
'coin_send': _normalizeCurrency(request.fromCurrency),
|
||||||
|
'coin_receive': _normalizeCurrency(request.toCurrency),
|
||||||
|
'amount_send': request.fromAmount,
|
||||||
|
'recipient': request.toAddress,
|
||||||
|
'ref': 'cake',
|
||||||
|
'markup': markup,
|
||||||
|
};
|
||||||
|
|
||||||
|
String? fromNetwork = _networkFor(request.fromCurrency);
|
||||||
|
String? toNetwork = _networkFor(request.toCurrency);
|
||||||
|
if (fromNetwork != null) body['coin_send_network'] = fromNetwork;
|
||||||
|
if (toNetwork != null) body['coin_receive_network'] = toNetwork;
|
||||||
|
|
||||||
|
final uri = Uri.https(apiAuthority, createOrder, params);
|
||||||
|
final response = await post(uri, body: body, headers: headers);
|
||||||
|
final responseBody = json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
|
||||||
|
if (response.statusCode == 400 || responseBody["success"] == false) {
|
||||||
|
final error = responseBody['errors'][0]['msg'] as String;
|
||||||
|
throw TradeNotCreatedException(description, description: error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.statusCode != 200)
|
||||||
|
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||||
|
|
||||||
|
final responseData = responseBody['data'] as Map<String, dynamic>;
|
||||||
|
|
||||||
|
return Trade(
|
||||||
|
id: responseData["order_id"] as String,
|
||||||
|
inputAddress: responseData["server_address"] as String,
|
||||||
|
amount: request.fromAmount,
|
||||||
|
from: request.fromCurrency,
|
||||||
|
to: request.toCurrency,
|
||||||
|
provider: description,
|
||||||
|
createdAt: DateTime.now(),
|
||||||
|
state: TradeState.created,
|
||||||
|
payoutAddress: request.toAddress,
|
||||||
|
isSendAll: isSendAll,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
print("error creating trade: ${e.toString()}");
|
||||||
|
throw TradeNotCreatedException(description, description: e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Trade> findTradeById({required String id}) async {
|
||||||
|
try {
|
||||||
|
final headers = <String, String>{};
|
||||||
|
final params = <String, dynamic>{};
|
||||||
|
var body = <String, dynamic>{
|
||||||
|
'order_id': id,
|
||||||
|
};
|
||||||
|
|
||||||
|
final uri = Uri.https(apiAuthority, createOrder, params);
|
||||||
|
final response = await post(uri, body: body, headers: headers);
|
||||||
|
final responseBody = json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
|
||||||
|
if (response.statusCode == 400 || responseBody["success"] == false) {
|
||||||
|
final error = responseBody['errors'][0]['msg'] as String;
|
||||||
|
throw TradeNotCreatedException(description, description: error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.statusCode != 200)
|
||||||
|
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||||
|
|
||||||
|
final responseData = responseBody['data'] as Map<String, dynamic>;
|
||||||
|
final fromCurrency = responseData['coin_send'] as String;
|
||||||
|
final from = CryptoCurrency.fromString(fromCurrency);
|
||||||
|
final toCurrency = responseData['coin_receive'] as String;
|
||||||
|
final to = CryptoCurrency.fromString(toCurrency);
|
||||||
|
final inputAddress = responseData['server_address'] as String;
|
||||||
|
final status = responseData['status'] as String;
|
||||||
|
final state = TradeState.deserialize(raw: status);
|
||||||
|
final response_id = responseData['order_id'] as String;
|
||||||
|
final expectedSendAmount = responseData['amount_send'] as String;
|
||||||
|
|
||||||
|
return Trade(
|
||||||
|
id: response_id,
|
||||||
|
from: from,
|
||||||
|
to: to,
|
||||||
|
provider: description,
|
||||||
|
inputAddress: inputAddress,
|
||||||
|
amount: expectedSendAmount,
|
||||||
|
state: state,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
print("error getting trade: ${e.toString()}");
|
||||||
|
throw TradeNotFoundException(
|
||||||
|
id,
|
||||||
|
provider: description,
|
||||||
|
description: e.toString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _normalizeCurrency(CryptoCurrency currency) {
|
||||||
|
switch (currency) {
|
||||||
|
default:
|
||||||
|
return currency.title.toUpperCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String? _networkFor(CryptoCurrency currency) {
|
||||||
|
switch (currency) {
|
||||||
|
case CryptoCurrency.usdt:
|
||||||
|
return "USDT_ERC20";
|
||||||
|
case CryptoCurrency.bnb:
|
||||||
|
return "BNB_BSC";
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,9 +5,6 @@ import 'package:cw_core/format_amount.dart';
|
||||||
import 'package:cw_core/hive_type_ids.dart';
|
import 'package:cw_core/hive_type_ids.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
part 'trade.g.dart';
|
|
||||||
|
|
||||||
@HiveType(typeId: Trade.typeId)
|
|
||||||
class Trade extends HiveObject {
|
class Trade extends HiveObject {
|
||||||
Trade({
|
Trade({
|
||||||
required this.id,
|
required this.id,
|
||||||
|
@ -32,6 +29,7 @@ class Trade extends HiveObject {
|
||||||
this.txId,
|
this.txId,
|
||||||
this.isRefund,
|
this.isRefund,
|
||||||
this.isSendAll,
|
this.isSendAll,
|
||||||
|
this.router,
|
||||||
}) {
|
}) {
|
||||||
if (provider != null) providerRaw = provider.raw;
|
if (provider != null) providerRaw = provider.raw;
|
||||||
|
|
||||||
|
@ -121,21 +119,26 @@ class Trade extends HiveObject {
|
||||||
@HiveField(21)
|
@HiveField(21)
|
||||||
bool? isSendAll;
|
bool? isSendAll;
|
||||||
|
|
||||||
|
@HiveField(22)
|
||||||
|
String? router;
|
||||||
|
|
||||||
static Trade fromMap(Map<String, Object?> map) {
|
static Trade fromMap(Map<String, Object?> map) {
|
||||||
return Trade(
|
return Trade(
|
||||||
id: map['id'] as String,
|
id: map['id'] as String,
|
||||||
provider: ExchangeProviderDescription.deserialize(raw: map['provider'] as int),
|
provider: ExchangeProviderDescription.deserialize(raw: map['provider'] as int),
|
||||||
from: CryptoCurrency.deserialize(raw: map['input'] as int),
|
from: CryptoCurrency.deserialize(raw: map['input'] as int),
|
||||||
to: CryptoCurrency.deserialize(raw: map['output'] as int),
|
to: CryptoCurrency.deserialize(raw: map['output'] as int),
|
||||||
createdAt:
|
createdAt:
|
||||||
map['date'] != null ? DateTime.fromMillisecondsSinceEpoch(map['date'] as int) : null,
|
map['date'] != null ? DateTime.fromMillisecondsSinceEpoch(map['date'] as int) : null,
|
||||||
amount: map['amount'] as String,
|
amount: map['amount'] as String,
|
||||||
walletId: map['wallet_id'] as String,
|
walletId: map['wallet_id'] as String,
|
||||||
fromWalletAddress: map['from_wallet_address'] as String?,
|
fromWalletAddress: map['from_wallet_address'] as String?,
|
||||||
memo: map['memo'] as String?,
|
memo: map['memo'] as String?,
|
||||||
txId: map['tx_id'] as String?,
|
txId: map['tx_id'] as String?,
|
||||||
isRefund: map['isRefund'] as bool?,
|
isRefund: map['isRefund'] as bool?,
|
||||||
isSendAll: map['isSendAll'] as bool?);
|
isSendAll: map['isSendAll'] as bool?,
|
||||||
|
router: map['router'] as String?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toMap() {
|
Map<String, dynamic> toMap() {
|
||||||
|
@ -152,8 +155,111 @@ class Trade extends HiveObject {
|
||||||
'tx_id': txId,
|
'tx_id': txId,
|
||||||
'isRefund': isRefund,
|
'isRefund': isRefund,
|
||||||
'isSendAll': isSendAll,
|
'isSendAll': isSendAll,
|
||||||
|
'router': router,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
String amountFormatted() => formatAmount(amount);
|
String amountFormatted() => formatAmount(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TradeAdapter extends TypeAdapter<Trade> {
|
||||||
|
@override
|
||||||
|
final int typeId = Trade.typeId;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Trade read(BinaryReader reader) {
|
||||||
|
final numOfFields = reader.readByte();
|
||||||
|
final fields = <int, dynamic>{};
|
||||||
|
for (int i = 0; i < numOfFields; i++) {
|
||||||
|
try {
|
||||||
|
fields[reader.readByte()] = reader.read();
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Trade(
|
||||||
|
id: fields[0] == null ? '' : fields[0] as String,
|
||||||
|
amount: fields[7] == null ? '' : fields[7] as String,
|
||||||
|
createdAt: fields[5] as DateTime?,
|
||||||
|
expiredAt: fields[6] as DateTime?,
|
||||||
|
inputAddress: fields[8] as String?,
|
||||||
|
extraId: fields[9] as String?,
|
||||||
|
outputTransaction: fields[10] as String?,
|
||||||
|
refundAddress: fields[11] as String?,
|
||||||
|
walletId: fields[12] as String?,
|
||||||
|
payoutAddress: fields[13] as String?,
|
||||||
|
password: fields[14] as String?,
|
||||||
|
providerId: fields[15] as String?,
|
||||||
|
providerName: fields[16] as String?,
|
||||||
|
fromWalletAddress: fields[17] as String?,
|
||||||
|
memo: fields[18] as String?,
|
||||||
|
txId: fields[19] as String?,
|
||||||
|
isRefund: fields[20] as bool?,
|
||||||
|
isSendAll: fields[21] as bool?,
|
||||||
|
router: fields[22] as String?,
|
||||||
|
)
|
||||||
|
..providerRaw = fields[1] == null ? 0 : fields[1] as int
|
||||||
|
..fromRaw = fields[2] == null ? 0 : fields[2] as int
|
||||||
|
..toRaw = fields[3] == null ? 0 : fields[3] as int
|
||||||
|
..stateRaw = fields[4] == null ? '' : fields[4] as String;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(BinaryWriter writer, Trade obj) {
|
||||||
|
writer
|
||||||
|
..writeByte(23)
|
||||||
|
..writeByte(0)
|
||||||
|
..write(obj.id)
|
||||||
|
..writeByte(1)
|
||||||
|
..write(obj.providerRaw)
|
||||||
|
..writeByte(2)
|
||||||
|
..write(obj.fromRaw)
|
||||||
|
..writeByte(3)
|
||||||
|
..write(obj.toRaw)
|
||||||
|
..writeByte(4)
|
||||||
|
..write(obj.stateRaw)
|
||||||
|
..writeByte(5)
|
||||||
|
..write(obj.createdAt)
|
||||||
|
..writeByte(6)
|
||||||
|
..write(obj.expiredAt)
|
||||||
|
..writeByte(7)
|
||||||
|
..write(obj.amount)
|
||||||
|
..writeByte(8)
|
||||||
|
..write(obj.inputAddress)
|
||||||
|
..writeByte(9)
|
||||||
|
..write(obj.extraId)
|
||||||
|
..writeByte(10)
|
||||||
|
..write(obj.outputTransaction)
|
||||||
|
..writeByte(11)
|
||||||
|
..write(obj.refundAddress)
|
||||||
|
..writeByte(12)
|
||||||
|
..write(obj.walletId)
|
||||||
|
..writeByte(13)
|
||||||
|
..write(obj.payoutAddress)
|
||||||
|
..writeByte(14)
|
||||||
|
..write(obj.password)
|
||||||
|
..writeByte(15)
|
||||||
|
..write(obj.providerId)
|
||||||
|
..writeByte(16)
|
||||||
|
..write(obj.providerName)
|
||||||
|
..writeByte(17)
|
||||||
|
..write(obj.fromWalletAddress)
|
||||||
|
..writeByte(18)
|
||||||
|
..write(obj.memo)
|
||||||
|
..writeByte(19)
|
||||||
|
..write(obj.txId)
|
||||||
|
..writeByte(20)
|
||||||
|
..write(obj.isRefund)
|
||||||
|
..writeByte(21)
|
||||||
|
..write(obj.isSendAll)
|
||||||
|
..writeByte(22)
|
||||||
|
..write(obj.router);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => typeId.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is TradeAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
|
||||||
TradeState(raw: 'waitingAuthorization', title: 'Waiting authorization');
|
TradeState(raw: 'waitingAuthorization', title: 'Waiting authorization');
|
||||||
static const failed = TradeState(raw: 'failed', title: 'Failed');
|
static const failed = TradeState(raw: 'failed', title: 'Failed');
|
||||||
static const completed = TradeState(raw: 'completed', title: 'Completed');
|
static const completed = TradeState(raw: 'completed', title: 'Completed');
|
||||||
|
static const expired = TradeState(raw: 'expired', title: 'Expired');
|
||||||
static const settling = TradeState(raw: 'settling', title: 'Settlement in progress');
|
static const settling = TradeState(raw: 'settling', title: 'Settlement in progress');
|
||||||
static const settled = TradeState(raw: 'settled', title: 'Settlement completed');
|
static const settled = TradeState(raw: 'settled', title: 'Settlement completed');
|
||||||
static const wait = TradeState(raw: 'wait', title: 'Waiting');
|
static const wait = TradeState(raw: 'wait', title: 'Waiting');
|
||||||
|
@ -39,7 +40,33 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
|
||||||
static const exchanging = TradeState(raw: 'exchanging', title: 'Exchanging');
|
static const exchanging = TradeState(raw: 'exchanging', title: 'Exchanging');
|
||||||
static const sending = TradeState(raw: 'sending', title: 'Sending');
|
static const sending = TradeState(raw: 'sending', title: 'Sending');
|
||||||
static const success = TradeState(raw: 'success', title: 'Success');
|
static const success = TradeState(raw: 'success', title: 'Success');
|
||||||
|
|
||||||
static TradeState deserialize({required String raw}) {
|
static TradeState deserialize({required String raw}) {
|
||||||
|
|
||||||
|
switch (raw) {
|
||||||
|
case '1':
|
||||||
|
return unpaid;
|
||||||
|
case '2':
|
||||||
|
return paidUnconfirmed;
|
||||||
|
case '3':
|
||||||
|
return sending;
|
||||||
|
case '4':
|
||||||
|
return confirmed;
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
return exchanging;
|
||||||
|
case '7':
|
||||||
|
return sending;
|
||||||
|
case '8':
|
||||||
|
return complete;
|
||||||
|
case '9':
|
||||||
|
return expired;
|
||||||
|
case '10':
|
||||||
|
return underpaid;
|
||||||
|
case '11':
|
||||||
|
return failed;
|
||||||
|
}
|
||||||
|
|
||||||
switch (raw) {
|
switch (raw) {
|
||||||
case 'NOT_FOUND':
|
case 'NOT_FOUND':
|
||||||
return notFound;
|
return notFound;
|
||||||
|
|
|
@ -5,7 +5,6 @@ import 'package:cake_wallet/core/secure_storage.dart';
|
||||||
import 'package:cake_wallet/entities/language_service.dart';
|
import 'package:cake_wallet/entities/language_service.dart';
|
||||||
import 'package:cake_wallet/buy/order.dart';
|
import 'package:cake_wallet/buy/order.dart';
|
||||||
import 'package:cake_wallet/locales/locale.dart';
|
import 'package:cake_wallet/locales/locale.dart';
|
||||||
import 'package:cake_wallet/store/yat/yat_store.dart';
|
|
||||||
import 'package:cake_wallet/utils/device_info.dart';
|
import 'package:cake_wallet/utils/device_info.dart';
|
||||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||||
|
@ -38,7 +37,6 @@ import 'package:cake_wallet/entities/template.dart';
|
||||||
import 'package:cake_wallet/exchange/trade.dart';
|
import 'package:cake_wallet/exchange/trade.dart';
|
||||||
import 'package:cake_wallet/exchange/exchange_template.dart';
|
import 'package:cake_wallet/exchange/exchange_template.dart';
|
||||||
import 'package:cake_wallet/src/screens/root/root.dart';
|
import 'package:cake_wallet/src/screens/root/root.dart';
|
||||||
import 'package:uni_links/uni_links.dart';
|
|
||||||
import 'package:cw_core/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
import 'package:cake_wallet/monero/monero.dart';
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
import 'package:cw_core/cake_hive.dart';
|
import 'package:cw_core/cake_hive.dart';
|
||||||
|
@ -46,9 +44,10 @@ import 'package:cw_core/window_size.dart';
|
||||||
|
|
||||||
final navigatorKey = GlobalKey<NavigatorState>();
|
final navigatorKey = GlobalKey<NavigatorState>();
|
||||||
final rootKey = GlobalKey<RootState>();
|
final rootKey = GlobalKey<RootState>();
|
||||||
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
|
final RouteObserver<PageRoute<dynamic>> routeObserver = RouteObserver<PageRoute<dynamic>>();
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
|
bool isAppRunning = false;
|
||||||
await runZonedGuarded(() async {
|
await runZonedGuarded(() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
@ -63,13 +62,42 @@ Future<void> main() async {
|
||||||
};
|
};
|
||||||
|
|
||||||
await setDefaultMinimumWindowSize();
|
await setDefaultMinimumWindowSize();
|
||||||
|
|
||||||
await CakeHive.close();
|
await CakeHive.close();
|
||||||
|
|
||||||
await initializeAppConfigs();
|
await initializeAppConfigs();
|
||||||
|
|
||||||
runApp(App());
|
runApp(App());
|
||||||
|
|
||||||
|
isAppRunning = true;
|
||||||
}, (error, stackTrace) async {
|
}, (error, stackTrace) async {
|
||||||
|
if (!isAppRunning) {
|
||||||
|
runApp(
|
||||||
|
MaterialApp(
|
||||||
|
debugShowCheckedModeBanner: false,
|
||||||
|
home: Scaffold(
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.only(top: 50, left: 20, right: 20, bottom: 20),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Error:\n${error.toString()}',
|
||||||
|
style: TextStyle(fontSize: 22),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Stack trace:\n${stackTrace.toString()}',
|
||||||
|
style: TextStyle(fontSize: 16),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace));
|
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -174,7 +202,7 @@ Future<void> initializeAppConfigs() async {
|
||||||
transactionDescriptions: transactionDescriptions,
|
transactionDescriptions: transactionDescriptions,
|
||||||
secureStorage: secureStorage,
|
secureStorage: secureStorage,
|
||||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||||
initialMigrationVersion: 33,
|
initialMigrationVersion: 34,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,61 +257,6 @@ class App extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppState extends State<App> with SingleTickerProviderStateMixin {
|
class AppState extends State<App> with SingleTickerProviderStateMixin {
|
||||||
AppState() : yatStore = getIt.get<YatStore>();
|
|
||||||
|
|
||||||
YatStore yatStore;
|
|
||||||
StreamSubscription? stream;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
//_handleIncomingLinks();
|
|
||||||
//_handleInitialUri();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _handleInitialUri() async {
|
|
||||||
try {
|
|
||||||
final uri = await getInitialUri();
|
|
||||||
print('uri: $uri');
|
|
||||||
if (uri == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!mounted) return;
|
|
||||||
//_fetchEmojiFromUri(uri);
|
|
||||||
} catch (e) {
|
|
||||||
if (!mounted) return;
|
|
||||||
print(e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleIncomingLinks() {
|
|
||||||
if (!kIsWeb) {
|
|
||||||
stream = getUriLinksStream().listen((Uri? uri) {
|
|
||||||
print('uri: $uri');
|
|
||||||
if (!mounted) return;
|
|
||||||
//_fetchEmojiFromUri(uri);
|
|
||||||
}, onError: (Object error) {
|
|
||||||
if (!mounted) return;
|
|
||||||
print('Error: $error');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _fetchEmojiFromUri(Uri uri) {
|
|
||||||
//final queryParameters = uri.queryParameters;
|
|
||||||
//if (queryParameters?.isEmpty ?? true) {
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
//final emoji = queryParameters['eid'];
|
|
||||||
//final refreshToken = queryParameters['refresh_token'];
|
|
||||||
//if ((emoji?.isEmpty ?? true)||(refreshToken?.isEmpty ?? true)) {
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
//yatStore.emoji = emoji;
|
|
||||||
//yatStore.refreshToken = refreshToken;
|
|
||||||
//yatStore.emojiIncommingSC.add(emoji);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Observer(builder: (BuildContext context) {
|
return Observer(builder: (BuildContext context) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -26,29 +26,32 @@ void startWalletSyncStatusChangeReaction(
|
||||||
SettingsStore settingsStore,
|
SettingsStore settingsStore,
|
||||||
Box<TransactionDescription> transactionDescription) {
|
Box<TransactionDescription> transactionDescription) {
|
||||||
_onWalletSyncStatusChangeReaction?.reaction.dispose();
|
_onWalletSyncStatusChangeReaction?.reaction.dispose();
|
||||||
|
|
||||||
_onWalletSyncStatusChangeReaction = reaction((_) => wallet.syncStatus, (SyncStatus status) async {
|
_onWalletSyncStatusChangeReaction = reaction((_) => wallet.syncStatus, (SyncStatus status) async {
|
||||||
if (status is ConnectedSyncStatus) {
|
try {
|
||||||
await wallet.startSync();
|
if (status is ConnectedSyncStatus) {
|
||||||
if (wallet.type == WalletType.haven) {
|
await wallet.startSync();
|
||||||
await updateHavenRate(fiatConversionStore);
|
if (wallet.type == WalletType.haven) {
|
||||||
|
await updateHavenRate(fiatConversionStore);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (status is SyncingSyncStatus) {
|
||||||
if (status is SyncingSyncStatus) {
|
await WakelockPlus.enable();
|
||||||
await WakelockPlus.enable();
|
}
|
||||||
}
|
if (status is SyncedSyncStatus || status is FailedSyncStatus) {
|
||||||
if (status is SyncedSyncStatus || status is FailedSyncStatus) {
|
await WakelockPlus.disable();
|
||||||
await WakelockPlus.disable();
|
|
||||||
|
|
||||||
if (status is SyncedSyncStatus &&
|
if (status is SyncedSyncStatus &&
|
||||||
(settingsStore.fiatApiMode != FiatApiMode.disabled ||
|
(settingsStore.fiatApiMode != FiatApiMode.disabled ||
|
||||||
settingsStore.showHistoricalFiatAmount)) {
|
settingsStore.showHistoricalFiatAmount)) {
|
||||||
_debounceTimer?.cancel();
|
_debounceTimer?.cancel();
|
||||||
_debounceTimer = Timer(Duration(milliseconds: 100), () async {
|
_debounceTimer = Timer(Duration(milliseconds: 100), () async {
|
||||||
await historicalRateUpdate(
|
await historicalRateUpdate(
|
||||||
wallet, settingsStore, fiatConversionStore, transactionDescription);
|
wallet, settingsStore, fiatConversionStore, transactionDescription);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
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';
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:cake_wallet/themes/theme_base.dart';
|
import 'package:cake_wallet/themes/theme_base.dart';
|
||||||
|
import 'package:cake_wallet/utils/route_aware.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cake_wallet/di.dart';
|
import 'package:cake_wallet/di.dart';
|
||||||
|
@ -32,6 +33,14 @@ abstract class BasePage extends StatelessWidget {
|
||||||
|
|
||||||
Widget? get endDrawer => null;
|
Widget? get endDrawer => null;
|
||||||
|
|
||||||
|
Function(BuildContext context)? get pushToWidget => null;
|
||||||
|
|
||||||
|
Function(BuildContext context)? get pushToNextWidget => null;
|
||||||
|
|
||||||
|
Function(BuildContext context)? get popWidget => null;
|
||||||
|
|
||||||
|
Function(BuildContext context)? get popNextWidget => null;
|
||||||
|
|
||||||
AppBarStyle get appBarStyle => AppBarStyle.regular;
|
AppBarStyle get appBarStyle => AppBarStyle.regular;
|
||||||
|
|
||||||
Widget Function(BuildContext, Widget)? get rootWrapper => null;
|
Widget Function(BuildContext, Widget)? get rootWrapper => null;
|
||||||
|
@ -162,15 +171,21 @@ abstract class BasePage extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final root = Scaffold(
|
final root = RouteAwareWidget(
|
||||||
key: _scaffoldKey,
|
child: Scaffold(
|
||||||
backgroundColor: pageBackgroundColor(context),
|
key: _scaffoldKey,
|
||||||
resizeToAvoidBottomInset: resizeToAvoidBottomInset,
|
backgroundColor: pageBackgroundColor(context),
|
||||||
extendBodyBehindAppBar: extendBodyBehindAppBar,
|
resizeToAvoidBottomInset: resizeToAvoidBottomInset,
|
||||||
endDrawer: endDrawer,
|
extendBodyBehindAppBar: extendBodyBehindAppBar,
|
||||||
appBar: appBar(context),
|
endDrawer: endDrawer,
|
||||||
body: body(context),
|
appBar: appBar(context),
|
||||||
floatingActionButton: floatingActionButton(context));
|
body: body(context),
|
||||||
|
floatingActionButton: floatingActionButton(context)),
|
||||||
|
pushToWidget: (context) => pushToWidget?.call(context),
|
||||||
|
pushToNextWidget: (context) => pushToNextWidget?.call(context),
|
||||||
|
popWidget: (context) => popWidget?.call(context),
|
||||||
|
popNextWidget: (context) => popNextWidget?.call(context),
|
||||||
|
);
|
||||||
|
|
||||||
return rootWrapper?.call(context, root) ?? root;
|
return rootWrapper?.call(context, root) ?? root;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
|
import 'package:cake_wallet/di.dart';
|
||||||
|
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||||
|
import 'package:cake_wallet/utils/permission_handler.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
class WebViewPage extends BasePage {
|
class WebViewPage extends BasePage {
|
||||||
WebViewPage(this._title, this._url);
|
WebViewPage(this._title, this._url);
|
||||||
|
@ -42,8 +46,9 @@ class WebViewPageBodyState extends State<WebViewPageBody> {
|
||||||
),
|
),
|
||||||
initialUrlRequest: URLRequest(url: WebUri.uri(widget.uri)),
|
initialUrlRequest: URLRequest(url: WebUri.uri(widget.uri)),
|
||||||
onPermissionRequest: (controller, request) async {
|
onPermissionRequest: (controller, request) async {
|
||||||
bool permissionGranted = await Permission.camera.status == PermissionStatus.granted;
|
final sharedPrefs = getIt.get<SharedPreferences>();
|
||||||
if (!permissionGranted) {
|
|
||||||
|
if (sharedPrefs.getBool(PreferencesKey.showCameraConsent) ?? true) {
|
||||||
final bool userConsent = await showPopUp<bool>(
|
final bool userConsent = await showPopUp<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
|
@ -65,9 +70,12 @@ class WebViewPageBodyState extends State<WebViewPageBody> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
permissionGranted = await Permission.camera.request().isGranted;
|
sharedPrefs.setBool(PreferencesKey.showCameraConsent, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool permissionGranted =
|
||||||
|
await PermissionHandler.checkPermission(Permission.camera, context);
|
||||||
|
|
||||||
return PermissionResponse(
|
return PermissionResponse(
|
||||||
resources: request.resources,
|
resources: request.resources,
|
||||||
action: permissionGranted
|
action: permissionGranted
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:io';
|
||||||
|
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/connect_device/debug_device_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/connect_device/widgets/device_tile.dart';
|
import 'package:cake_wallet/src/screens/connect_device/widgets/device_tile.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/responsive_layout_util.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
|
@ -78,15 +79,13 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
Future.delayed(
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
Duration(seconds: 1),
|
_bleRefreshTimer = Timer.periodic(Duration(seconds: 1), (_) => _refreshBleDevices());
|
||||||
() => _bleRefresh = ledger.scan().listen((device) => setState(() => bleDevices.add(device))),
|
|
||||||
);
|
|
||||||
// _bleRefreshTimer = Timer.periodic(Duration(seconds: 1), (_) => _refreshBleDevices());
|
|
||||||
|
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
_usbRefreshTimer = Timer.periodic(Duration(seconds: 1), (_) => _refreshUsbDevices());
|
_usbRefreshTimer = Timer.periodic(Duration(seconds: 1), (_) => _refreshUsbDevices());
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -103,14 +102,16 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _refreshBleDevices() async {
|
Future<void> _refreshBleDevices() async {
|
||||||
final isBleEnabled = await Permission.bluetooth.serviceStatus.isEnabled;
|
try {
|
||||||
|
_bleRefresh = ledger.scan().listen((device) => setState(() => bleDevices.add(device)))
|
||||||
setState(() => bleIsEnabled = isBleEnabled);
|
..onError((e) {
|
||||||
|
throw e.toString();
|
||||||
if (isBleEnabled) {
|
});
|
||||||
_bleRefresh = ledger.scan().listen((device) => setState(() => bleDevices.add(device)));
|
setState(() => bleIsEnabled = true);
|
||||||
_bleRefreshTimer?.cancel();
|
_bleRefreshTimer?.cancel();
|
||||||
_bleRefreshTimer = null;
|
_bleRefreshTimer = null;
|
||||||
|
} catch (e) {
|
||||||
|
setState(() => bleIsEnabled = false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +143,15 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// DeviceTile(
|
||||||
|
// onPressed: () => Navigator.of(context).push(
|
||||||
|
// MaterialPageRoute<void>(
|
||||||
|
// builder: (BuildContext context) => DebugDevicePage(),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// title: "Debug Ledger",
|
||||||
|
// leading: imageLedger,
|
||||||
|
// ),
|
||||||
if (!bleIsEnabled)
|
if (!bleIsEnabled)
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||||
|
|
|
@ -46,6 +46,7 @@ class ContactPage extends BasePage {
|
||||||
final TextEditingController _nameController;
|
final TextEditingController _nameController;
|
||||||
final TextEditingController _currencyTypeController;
|
final TextEditingController _currencyTypeController;
|
||||||
final TextEditingController _addressController;
|
final TextEditingController _addressController;
|
||||||
|
bool _isEffectsApplied = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
|
@ -53,15 +54,7 @@ class ContactPage extends BasePage {
|
||||||
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
|
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
|
||||||
height: 8);
|
height: 8);
|
||||||
|
|
||||||
reaction((_) => contactViewModel.state, (ExecutionState state) {
|
_setEffects(context);
|
||||||
if (state is FailureState) {
|
|
||||||
_onContactSavingFailure(context, state.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state is ExecutedSuccessfullyState) {
|
|
||||||
_onContactSavedSuccessfully(context);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Observer(
|
return Observer(
|
||||||
builder: (_) => ScrollableWithBottomSection(
|
builder: (_) => ScrollableWithBottomSection(
|
||||||
|
@ -177,4 +170,22 @@ class ContactPage extends BasePage {
|
||||||
|
|
||||||
void _onContactSavedSuccessfully(BuildContext context) =>
|
void _onContactSavedSuccessfully(BuildContext context) =>
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
void _setEffects(BuildContext context) {
|
||||||
|
if (_isEffectsApplied) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isEffectsApplied = true;
|
||||||
|
|
||||||
|
reaction((_) => contactViewModel.state, (ExecutionState state) {
|
||||||
|
if (state is FailureState) {
|
||||||
|
_onContactSavingFailure(context, state.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state is ExecutedSuccessfullyState) {
|
||||||
|
_onContactSavedSuccessfully(context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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';
|
||||||
|
@ -36,7 +36,7 @@ import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart'
|
||||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||||
|
|
||||||
class DashboardPage extends StatelessWidget {
|
class DashboardPage extends StatefulWidget {
|
||||||
DashboardPage({
|
DashboardPage({
|
||||||
required this.bottomSheetService,
|
required this.bottomSheetService,
|
||||||
required this.balancePage,
|
required this.balancePage,
|
||||||
|
@ -50,43 +50,71 @@ class DashboardPage extends StatelessWidget {
|
||||||
final WalletAddressListViewModel addressListViewModel;
|
final WalletAddressListViewModel addressListViewModel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
State<DashboardPage> createState() => _DashboardPageState();
|
||||||
final screenHeight = MediaQuery.of(context).size.height;
|
}
|
||||||
return Scaffold(
|
|
||||||
body: Observer(
|
|
||||||
builder: (_) {
|
|
||||||
final dashboardPageView = RefreshIndicator(
|
|
||||||
displacement: screenHeight * 0.1,
|
|
||||||
onRefresh: () async => await dashboardViewModel.refreshDashboard(),
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
physics: AlwaysScrollableScrollPhysics(),
|
|
||||||
child: Container(
|
|
||||||
height: screenHeight,
|
|
||||||
child: _DashboardPageView(
|
|
||||||
balancePage: balancePage,
|
|
||||||
bottomSheetService: bottomSheetService,
|
|
||||||
dashboardViewModel: dashboardViewModel,
|
|
||||||
addressListViewModel: addressListViewModel,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (DeviceInfo.instance.isDesktop) {
|
class _DashboardPageState extends State<DashboardPage> {
|
||||||
if (responsiveLayoutUtil.screenWidth >
|
@override
|
||||||
ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) {
|
void initState() {
|
||||||
return getIt.get<DesktopSidebarWrapper>();
|
super.initState();
|
||||||
} else {
|
|
||||||
return dashboardPageView;
|
bool isMobileLayout =
|
||||||
}
|
responsiveLayoutUtil.screenWidth < ResponsiveLayoutUtilBase.kMobileThreshold;
|
||||||
} else if (responsiveLayoutUtil.shouldRenderMobileUI) {
|
|
||||||
return dashboardPageView;
|
reaction((_) => responsiveLayoutUtil.screenWidth, (screenWidth) {
|
||||||
} else {
|
// Check if it was previously in mobile layout, and now changing to desktop
|
||||||
return getIt.get<DesktopSidebarWrapper>();
|
if (isMobileLayout &&
|
||||||
}
|
screenWidth > ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) {
|
||||||
},
|
setState(() {
|
||||||
|
isMobileLayout = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it was previously in desktop layout, and now changing to mobile
|
||||||
|
if (!isMobileLayout &&
|
||||||
|
screenWidth <= ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) {
|
||||||
|
setState(() {
|
||||||
|
isMobileLayout = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Widget dashboardChild;
|
||||||
|
|
||||||
|
final dashboardPageView = RefreshIndicator(
|
||||||
|
displacement: responsiveLayoutUtil.screenHeight * 0.1,
|
||||||
|
onRefresh: () async => await widget.dashboardViewModel.refreshDashboard(),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
physics: AlwaysScrollableScrollPhysics(),
|
||||||
|
child: Container(
|
||||||
|
height: responsiveLayoutUtil.screenHeight,
|
||||||
|
child: _DashboardPageView(
|
||||||
|
balancePage: widget.balancePage,
|
||||||
|
bottomSheetService: widget.bottomSheetService,
|
||||||
|
dashboardViewModel: widget.dashboardViewModel,
|
||||||
|
addressListViewModel: widget.addressListViewModel,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (DeviceInfo.instance.isDesktop) {
|
||||||
|
if (responsiveLayoutUtil.screenWidth >
|
||||||
|
ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) {
|
||||||
|
dashboardChild = getIt.get<DesktopSidebarWrapper>();
|
||||||
|
} else {
|
||||||
|
dashboardChild = dashboardPageView;
|
||||||
|
}
|
||||||
|
} else if (responsiveLayoutUtil.shouldRenderMobileUI) {
|
||||||
|
dashboardChild = dashboardPageView;
|
||||||
|
} else {
|
||||||
|
dashboardChild = getIt.get<DesktopSidebarWrapper>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(body: dashboardChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,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),
|
||||||
))
|
))
|
||||||
|
@ -117,27 +121,33 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||||
if (selectedWallet.isCurrent || !selectedWallet.isEnabled) {
|
if (selectedWallet.isCurrent || !selectedWallet.isEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final confirmed = await showPopUp<bool>(
|
|
||||||
context: context,
|
|
||||||
builder: (dialogContext) {
|
|
||||||
return AlertWithTwoActions(
|
|
||||||
alertTitle: S.of(context).change_wallet_alert_title,
|
|
||||||
alertContent: S.of(context).change_wallet_alert_content(selectedWallet.name),
|
|
||||||
leftButtonText: S.of(context).cancel,
|
|
||||||
rightButtonText: S.of(context).change,
|
|
||||||
actionLeftButton: () => Navigator.of(dialogContext).pop(false),
|
|
||||||
actionRightButton: () => Navigator.of(dialogContext).pop(true));
|
|
||||||
}) ??
|
|
||||||
false;
|
|
||||||
|
|
||||||
if (confirmed) {
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
await _loadWallet(selectedWallet);
|
final confirmed = await showPopUp<bool>(
|
||||||
}
|
context: context,
|
||||||
|
builder: (dialogContext) {
|
||||||
|
return AlertWithTwoActions(
|
||||||
|
alertTitle: S.of(context).change_wallet_alert_title,
|
||||||
|
alertContent: S.of(context).change_wallet_alert_content(selectedWallet.name),
|
||||||
|
leftButtonText: S.of(context).cancel,
|
||||||
|
rightButtonText: S.of(context).change,
|
||||||
|
actionLeftButton: () => Navigator.of(dialogContext).pop(false),
|
||||||
|
actionRightButton: () => Navigator.of(dialogContext).pop(true));
|
||||||
|
}) ??
|
||||||
|
false;
|
||||||
|
|
||||||
|
if (confirmed) {
|
||||||
|
await _loadWallet(selectedWallet);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
@ -157,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;
|
||||||
|
@ -165,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,
|
||||||
|
@ -195,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({
|
||||||
|
@ -69,14 +73,14 @@ class BalancePage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
labelColor:
|
labelColor:
|
||||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||||
dividerColor:
|
dividerColor: Colors.transparent,
|
||||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
|
||||||
indicatorColor:
|
indicatorColor:
|
||||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||||
unselectedLabelColor: Theme.of(context)
|
unselectedLabelColor: Theme.of(context)
|
||||||
.extension<DashboardPageTheme>()!
|
.extension<DashboardPageTheme>()!
|
||||||
.pageTitleTextColor
|
.pageTitleTextColor
|
||||||
.withOpacity(0.5),
|
.withOpacity(0.5),
|
||||||
|
tabAlignment: TabAlignment.start,
|
||||||
tabs: [
|
tabs: [
|
||||||
Tab(text: 'My Crypto'),
|
Tab(text: 'My Crypto'),
|
||||||
Tab(text: 'My NFTs'),
|
Tab(text: 'My NFTs'),
|
||||||
|
@ -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)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -99,6 +99,14 @@ class ExchangePage extends BasePage {
|
||||||
@override
|
@override
|
||||||
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Function(BuildContext)? get pushToNextWidget => (context) {
|
||||||
|
FocusScopeNode currentFocus = FocusScope.of(context);
|
||||||
|
if (!currentFocus.hasPrimaryFocus) {
|
||||||
|
currentFocus.focusedChild?.unfocus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget middle(BuildContext context) => Row(
|
Widget middle(BuildContext context) => Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
|
|
@ -84,12 +84,7 @@ class IoniaGiftCardDetailPage extends BasePage {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return RouteAwareWidget(
|
return ScrollableWithBottomSection(
|
||||||
pushToWidget: ()=> viewModel.increaseBrightness(),
|
|
||||||
pushToNextWidget: ()=> DeviceDisplayBrightness.setBrightness(viewModel.brightness),
|
|
||||||
popNextWidget: ()=> viewModel.increaseBrightness(),
|
|
||||||
popWidget: ()=> DeviceDisplayBrightness.setBrightness(viewModel.brightness),
|
|
||||||
child: ScrollableWithBottomSection(
|
|
||||||
contentPadding: EdgeInsets.all(24),
|
contentPadding: EdgeInsets.all(24),
|
||||||
content: Column(
|
content: Column(
|
||||||
children: [
|
children: [
|
||||||
|
@ -168,7 +163,7 @@ class IoniaGiftCardDetailPage extends BasePage {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildIoniaTile(BuildContext context, {required String title, required String subTitle}) {
|
Widget buildIoniaTile(BuildContext context, {required String title, required String subTitle}) {
|
||||||
|
|
|
@ -38,6 +38,14 @@ class NewWalletPage extends BasePage {
|
||||||
@override
|
@override
|
||||||
String get title => S.current.new_wallet;
|
String get title => S.current.new_wallet;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Function(BuildContext)? get pushToNextWidget => (context) {
|
||||||
|
FocusScopeNode currentFocus = FocusScope.of(context);
|
||||||
|
if (!currentFocus.hasPrimaryFocus) {
|
||||||
|
currentFocus.focusedChild?.unfocus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) => WalletNameForm(
|
Widget body(BuildContext context) => WalletNameForm(
|
||||||
_walletNewVM,
|
_walletNewVM,
|
||||||
|
|
|
@ -34,6 +34,14 @@ class NewWalletTypePage extends BasePage {
|
||||||
String get title =>
|
String get title =>
|
||||||
isCreate ? S.current.wallet_list_create_new_wallet : S.current.wallet_list_restore_wallet;
|
isCreate ? S.current.wallet_list_create_new_wallet : S.current.wallet_list_restore_wallet;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Function(BuildContext)? get pushToNextWidget => (context) {
|
||||||
|
FocusScopeNode currentFocus = FocusScope.of(context);
|
||||||
|
if (!currentFocus.hasPrimaryFocus) {
|
||||||
|
currentFocus.focusedChild?.unfocus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) => WalletTypeForm(
|
Widget body(BuildContext context) => WalletTypeForm(
|
||||||
onTypeSelected: onTypeSelected,
|
onTypeSelected: onTypeSelected,
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,14 @@ class RestoreFromBackupPage extends BasePage {
|
||||||
@override
|
@override
|
||||||
String get title => S.current.restore_title_from_backup;
|
String get title => S.current.restore_title_from_backup;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Function(BuildContext)? get pushToNextWidget => (context) {
|
||||||
|
FocusScopeNode currentFocus = FocusScope.of(context);
|
||||||
|
if (!currentFocus.hasPrimaryFocus) {
|
||||||
|
currentFocus.focusedChild?.unfocus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
reaction((_) => restoreFromBackupViewModel.state, (ExecutionState state) {
|
reaction((_) => restoreFromBackupViewModel.state, (ExecutionState state) {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:cake_wallet/core/execution_state.dart';
|
import 'package:cake_wallet/core/execution_state.dart';
|
||||||
import 'package:cake_wallet/di.dart';
|
import 'package:cake_wallet/di.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
@ -13,6 +15,9 @@ import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
|
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
|
||||||
import 'package:cake_wallet/view_model/restore/wallet_restore_from_qr_code.dart';
|
import 'package:cake_wallet/view_model/restore/wallet_restore_from_qr_code.dart';
|
||||||
|
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||||
|
import 'package:cw_core/hardware/device_connection_type.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
||||||
|
@ -24,6 +29,19 @@ class RestoreOptionsPage extends BasePage {
|
||||||
|
|
||||||
final bool isNewInstall;
|
final bool isNewInstall;
|
||||||
|
|
||||||
|
bool get _doesSupportHardwareWallets {
|
||||||
|
if (!DeviceInfo.instance.isMobile) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMoneroOnly) {
|
||||||
|
return DeviceConnectionType.supportedConnectionTypes(WalletType.monero, Platform.isIOS)
|
||||||
|
.isNotEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
final imageColor = Theme.of(context).extension<OptionTileTheme>()!.titleColor;
|
final imageColor = Theme.of(context).extension<OptionTileTheme>()!.titleColor;
|
||||||
|
@ -57,7 +75,7 @@ class RestoreOptionsPage extends BasePage {
|
||||||
description: S.of(context).restore_description_from_backup,
|
description: S.of(context).restore_description_from_backup,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (DeviceInfo.instance.isMobile)
|
if (_doesSupportHardwareWallets)
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 24),
|
padding: EdgeInsets.only(top: 24),
|
||||||
child: OptionTile(
|
child: OptionTile(
|
||||||
|
|
|
@ -101,6 +101,14 @@ class WalletRestorePage extends BasePage {
|
||||||
// String? derivationPath = null;
|
// String? derivationPath = null;
|
||||||
DerivationInfo? derivationInfo;
|
DerivationInfo? derivationInfo;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Function(BuildContext)? get pushToNextWidget => (context) {
|
||||||
|
FocusScopeNode currentFocus = FocusScope.of(context);
|
||||||
|
if (!currentFocus.hasPrimaryFocus) {
|
||||||
|
currentFocus.focusedChild?.unfocus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
reaction((_) => walletRestoreViewModel.state, (ExecutionState state) {
|
reaction((_) => walletRestoreViewModel.state, (ExecutionState state) {
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:cake_wallet/core/auth_service.dart';
|
import 'package:cake_wallet/core/auth_service.dart';
|
||||||
import 'package:cake_wallet/core/totp_request_details.dart';
|
import 'package:cake_wallet/core/totp_request_details.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
|
||||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
|
||||||
import 'package:cake_wallet/utils/device_info.dart';
|
import 'package:cake_wallet/utils/device_info.dart';
|
||||||
import 'package:cake_wallet/utils/payment_request.dart';
|
|
||||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -13,7 +10,6 @@ import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
import 'package:cake_wallet/store/app_store.dart';
|
||||||
import 'package:cake_wallet/store/authentication_store.dart';
|
import 'package:cake_wallet/store/authentication_store.dart';
|
||||||
import 'package:cake_wallet/entities/qr_scanner.dart';
|
import 'package:cake_wallet/entities/qr_scanner.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:uni_links/uni_links.dart';
|
import 'package:uni_links/uni_links.dart';
|
||||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
|
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
|
||||||
|
|
|
@ -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';
|
||||||
|
@ -35,7 +36,6 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
class SendPage extends BasePage {
|
class SendPage extends BasePage {
|
||||||
|
@ -66,6 +66,14 @@ class SendPage extends BasePage {
|
||||||
@override
|
@override
|
||||||
bool get extendBodyBehindAppBar => true;
|
bool get extendBodyBehindAppBar => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Function(BuildContext)? get pushToNextWidget => (context) {
|
||||||
|
FocusScopeNode currentFocus = FocusScope.of(context);
|
||||||
|
if (!currentFocus.hasPrimaryFocus) {
|
||||||
|
currentFocus.focusedChild?.unfocus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget? leading(BuildContext context) {
|
Widget? leading(BuildContext context) {
|
||||||
final _backButton = Icon(
|
final _backButton = Icon(
|
||||||
|
@ -373,17 +381,17 @@ class SendPage extends BasePage {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sendViewModel.wallet.isHardwareWallet) {
|
if (sendViewModel.wallet.isHardwareWallet) {
|
||||||
if (!sendViewModel.ledgerViewModel.isConnected) {
|
if (!sendViewModel.ledgerViewModel!.isConnected) {
|
||||||
await Navigator.of(context).pushNamed(Routes.connectDevices,
|
await Navigator.of(context).pushNamed(Routes.connectDevices,
|
||||||
arguments: ConnectDevicePageParams(
|
arguments: ConnectDevicePageParams(
|
||||||
walletType: sendViewModel.walletType,
|
walletType: sendViewModel.walletType,
|
||||||
onConnectDevice: (BuildContext context, _) {
|
onConnectDevice: (BuildContext context, _) {
|
||||||
sendViewModel.ledgerViewModel.setLedger(sendViewModel.wallet);
|
sendViewModel.ledgerViewModel!.setLedger(sendViewModel.wallet);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
sendViewModel.ledgerViewModel.setLedger(sendViewModel.wallet);
|
sendViewModel.ledgerViewModel!.setLedger(sendViewModel.wallet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,6 +429,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();
|
||||||
|
|
|
@ -32,6 +32,14 @@ class SendTemplatePage extends BasePage {
|
||||||
@override
|
@override
|
||||||
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Function(BuildContext)? get pushToNextWidget => (context) {
|
||||||
|
FocusScopeNode currentFocus = FocusScope.of(context);
|
||||||
|
if (!currentFocus.hasPrimaryFocus) {
|
||||||
|
currentFocus.focusedChild?.unfocus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget trailing(context) => Observer(builder: (_) {
|
Widget trailing(context) => Observer(builder: (_) {
|
||||||
return sendTemplateViewModel.recipients.length > 1
|
return sendTemplateViewModel.recipients.length > 1
|
||||||
|
|
|
@ -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) ...[
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:cake_wallet/routes.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/typography.dart';
|
import 'package:cake_wallet/typography.dart';
|
||||||
|
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cake_wallet/router.dart' as Router;
|
import 'package:cake_wallet/router.dart' as Router;
|
||||||
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||||
|
@ -10,7 +11,9 @@ import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||||
final _settingsNavigatorKey = GlobalKey<NavigatorState>();
|
final _settingsNavigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
|
||||||
class DesktopSettingsPage extends StatefulWidget {
|
class DesktopSettingsPage extends StatefulWidget {
|
||||||
const DesktopSettingsPage({super.key});
|
const DesktopSettingsPage(this.dashboardViewModel, {super.key});
|
||||||
|
|
||||||
|
final DashboardViewModel dashboardViewModel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DesktopSettingsPage> createState() => _DesktopSettingsPageState();
|
State<DesktopSettingsPage> createState() => _DesktopSettingsPageState();
|
||||||
|
@ -51,6 +54,12 @@ class _DesktopSettingsPageState extends State<DesktopSettingsPage> {
|
||||||
padding: EdgeInsets.only(top: 0),
|
padding: EdgeInsets.only(top: 0),
|
||||||
itemBuilder: (_, index) {
|
itemBuilder: (_, index) {
|
||||||
final item = SettingActions.desktopSettings[index];
|
final item = SettingActions.desktopSettings[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(
|
||||||
isLastTile: isLastTile,
|
isLastTile: isLastTile,
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue