Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-66-open-app-from-qr-code

 Conflicts:
	lib/di.dart
	lib/src/screens/send/send_page.dart
	lib/src/screens/send/widgets/send_card.dart
	lib/utils/payment_request.dart
	res/values/strings_de.arb
	res/values/strings_en.arb
	res/values/strings_es.arb
	res/values/strings_fr.arb
	res/values/strings_hi.arb
	res/values/strings_hr.arb
	res/values/strings_it.arb
	res/values/strings_ja.arb
	res/values/strings_ko.arb
	res/values/strings_nl.arb
	res/values/strings_pl.arb
	res/values/strings_pt.arb
	res/values/strings_ru.arb
	res/values/strings_uk.arb
	res/values/strings_zh.arb
This commit is contained in:
OmarHatem 2022-11-08 14:44:58 +02:00
commit 7c7de65cdf
575 changed files with 10219 additions and 6811 deletions

View file

@ -1,51 +1,73 @@
include: package:lints/recommended.yaml
analyzer: analyzer:
strong-mode: exclude: [
implicit-casts: false build/**,
implicit-dynamic: false lib/**.g.dart,
exclude: [build/**, lib/generated/*.dart, lib/**.g.dart, cw_monero/ios/External/**, cw_shared_external/**, shared_external/**] cw_core/lib/**.g.dart,
cw_haven/lib/**.g.dart,
cw_monero/lib/**.g.dart,
lib/generated/*.dart,
cw_monero/ios/External/**,
cw_shared_external/**,
shared_external/**]
language:
strict-casts: true
strict-raw-types: true
linter: linter:
rules: rules:
- always_declare_return_types
- annotate_overrides
- avoid_empty_else
- avoid_init_to_null
- avoid_return_types_on_setters
- await_only_futures
- camel_case_types
- cancel_subscriptions - cancel_subscriptions
- close_sinks
- comment_references
- constant_identifier_names # analyzer:
- control_flow_in_finally # strong-mode:
- empty_catches # implicit-casts: false
- empty_constructor_bodies # implicit-dynamic: false
- empty_statements # exclude: [build/**, lib/generated/*.dart, lib/**.g.dart, cw_monero/ios/External/**, cw_shared_external/**, shared_external/**]
- hash_and_equals
- invariant_booleans # linter:
- iterable_contains_unrelated_type # rules:
- library_names # - always_declare_return_types
- library_prefixes # - annotate_overrides
- list_remove_unrelated_type # - avoid_empty_else
- literal_only_boolean_expressions # - avoid_init_to_null
- non_constant_identifier_names # - avoid_return_types_on_setters
- one_member_abstracts # - await_only_futures
- only_throw_errors # - camel_case_types
- overridden_fields # - cancel_subscriptions
- package_api_docs # - close_sinks
- package_names # - comment_references
- package_prefixed_library_names # - constant_identifier_names
- parameter_assignments # - control_flow_in_finally
- prefer_final_fields # - empty_catches
- prefer_final_locals # - empty_constructor_bodies
- prefer_is_not_empty # - empty_statements
- slash_for_doc_comments # - hash_and_equals
- sort_constructors_first # - invariant_booleans
- sort_unnamed_constructors_first # - iterable_contains_unrelated_type
- test_types_in_equals # - library_names
- throw_in_finally # - library_prefixes
- type_init_formals # - list_remove_unrelated_type
- unawaited_futures # - literal_only_boolean_expressions
- unnecessary_getters_setters # - non_constant_identifier_names
- unrelated_type_equality_checks # - one_member_abstracts
- valid_regexps # - only_throw_errors
# - overridden_fields
# - package_api_docs
# - package_names
# - package_prefixed_library_names
# - parameter_assignments
# - prefer_final_fields
# - prefer_final_locals
# - prefer_is_not_empty
# - slash_for_doc_comments
# - sort_constructors_first
# - sort_unnamed_constructors_first
# - test_types_in_equals
# - throw_in_finally
# - type_init_formals
# - unawaited_futures
# - unnecessary_getters_setters
# - unrelated_type_equality_checks
# - valid_regexps

View file

@ -1,2 +1,2 @@
connection.project.dir= connection.project.dir=
eclipse.preferences.version=1 eclipse.preferences.version=1

View file

@ -37,7 +37,7 @@ if (appPropertiesFile.exists()) {
} }
android { android {
compileSdkVersion 29 compileSdkVersion 33
lintOptions { lintOptions {
disable 'InvalidPackage' disable 'InvalidPackage'
@ -80,6 +80,8 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
ndkVersion "25.1.8937393"
} }
flutter { flutter {

View file

@ -1,4 +1,5 @@
buildscript { buildscript {
ext.kotlin_version = '1.5.10'
repositories { repositories {
google() google()
jcenter() jcenter()
@ -7,6 +8,7 @@ buildscript {
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.1.3' classpath 'com.android.tools.build:gradle:4.1.3'
classpath 'com.google.gms:google-services:4.3.8' classpath 'com.google.gms:google-services:4.3.8'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }

View file

@ -5,31 +5,31 @@
}, },
{ {
"question" : "Comment envoyer des Monero vers une plateforme d'échange qui nécessite un ID de paiement ?", "question" : "Comment envoyer des Monero vers une plateforme d'échange qui nécessite un ID de paiement ?",
"answer" : "Appuyez sur le bouton envoyer de l'écran du Wallet. Ensuite, copiez l'adresse de dépôt de la plateforme d'échange et collez là dans le champ adresse. Puis, copiez l'ID de paiement fourni par la plateforme d'échange et copiez le dans le champ ID de paiement. Enfin, entrez le montant que vous souhaitez envoyer et vous êtes fin prêt !\n" "answer" : "Appuyez sur le bouton envoyer de l'écran du Portefeuille (Wallet). Ensuite, copiez l'adresse de dépôt de la plateforme d'échange et collez là dans le champ adresse. Puis, copiez l'ID de paiement fourni par la plateforme d'échange et copiez le dans le champ ID de paiement. Enfin, entrez le montant que vous souhaitez envoyer et vous êtes fin prêt !\n"
}, },
{ {
"question" : "Que faire si j'oublie d'entrer l'ID de paiement quand j'envoie des Monero vers une plateforme d'échange ?", "question" : "Que faire si j'oublie d'entrer l'ID de paiement quand j'envoie des Monero vers une plateforme d'échange ?",
"answer" : "Bien que notre service de support ne puisse pas vous aider directement pour ce type de souci, c'est un problème très courant que la plupart des plateformes d'échange ont l'habitude de gérer. Contactez simplement le support de la plateforme d'échange, expliquez que vous avez oublié d'inclure l'ID de paiement et envoyez leur l'ID de transaction comme preuve. Vous pouvez visualiser l'ID de transaction en tapant sur transaction sur l'écran de votre wallet.\n" "answer" : "Bien que notre service de support ne puisse pas vous aider directement pour ce type de souci, c'est un problème très courant que la plupart des plateformes d'échange ont l'habitude de gérer. Contactez simplement le support de la plateforme d'échange, expliquez que vous avez oublié d'inclure l'ID de paiement et envoyez leur l'ID de transaction comme preuve. Vous pouvez visualiser l'ID de transaction en tapant sur transaction sur l'écran de votre portefeuille (wallet).\n"
}, },
{ {
"question" : "Que signifient \"seed\" et \"clefs\" ?", "question" : "Que signifient \"phrase secrète (seed)\" et \"clefs\" ?",
"answer" : "Vos clefs encodent l'information privée de votre wallet, ce sont elles qui permettent de dépenser vos fonds et de visualiser les transactions entrantes.\nVotre seed est simplement une version de votre clef privée sous une forme plus simple à recopier. Votre seed et vos clefs sont la même chose, juste sous des formes différentes !\nNE DONNEZ JAMAIS votre seed ou vos clefs à quiconque. Vos fonds seront dérobés si vous donner votre seed ou vos clefs. Merci d'écrire cependant votre seed et de le stocker en lieu sûr (afin de vous permettre de restaurer votre wallet si vous perdez votre téléphone.)\n" "answer" : "Vos clefs encodent l'information privée de votre portefeuille (wallet), ce sont elles qui permettent de dépenser vos fonds et de visualiser les transactions entrantes.\nVotre phrase secrète (seed) est simplement une version de votre clef privée sous une forme plus simple à recopier. Votre phrase secrète et vos clefs sont la même chose, juste sous des formes différentes !\nNE DONNEZ JAMAIS votre phrase secrète ou vos clefs à quiconque. Vos fonds seront dérobés si vous donnez votre phrase secrète ou vos clefs. Merci d'écrire cependant votre phrase secrète et de la stocker en lieu sûr (afin de vous permettre de restaurer votre portefeuille si vous perdez votre téléphone.)\n"
}, },
{ {
"question" : "Combien de wallets puis-je créer ?", "question" : "Combien de portefeuilles (wallets) puis-je créer ?",
"answer" : "Il n'y a pas de limite ! Vous pouvez créer autant de wallets que vous le souhaitez.\n" "answer" : "Il n'y a pas de limite ! Vous pouvez créer autant de portefeuilles (wallets) que vous le souhaitez.\n"
}, },
{ {
"question" : "Commen puis-je restarurer mon wallet ?", "question" : "Commen puis-je restarurer mon portefeuille (wallet) ?",
"answer" : "Appuyez sur le menu •••, sélectionnez Wallets, puis choisissez Restaurer un Wallet. Entrez alors votre seed (ou vos clefs), et de façon optionnelle une date antérieure à la première transaction de votre wallet (cela permettra d'accélérer le processus de synchronisation). Vous pourrez avoir besoin de maintenir l'application ouverte pendant 15 à 30 minutes afin de restaurer complètement votre wallet.\n" "answer" : "Appuyez sur le menu •••, sélectionnez Portefeuilles (Wallets), puis choisissez Restaurer un Portefeuille. Entrez alors votre phrase secrète (seed) (ou vos clefs), et de façon optionnelle une date antérieure à la première transaction de votre portefeuille (cela permettra d'accélérer le processus de synchronisation). Vous pourrez avoir besoin de maintenir l'application ouverte pendant 15 à 30 minutes afin de restaurer complètement votre portefeuille.\n"
}, },
{ {
"question" : "Que puis-je faire si je perds mon seed ?", "question" : "Que puis-je faire si je perds ma phrase secrète (seed) ?",
"answer" : "Si vous oubliez votre seed, il y a des chances que vous l'ayez inscrit quelque part. Vérifiez vos notes et regardez sur votre ordinateur. Si vous ne parvenez pas à le retrouver, il est possible que vous ayez effectué une sauvegarde de Cake Wallet (dans ce cas vous pourrez restaurer d'après cette sauvegarde). Si aucune des ces options ne convient, malheureusement il n'y a plus rien à faire, vos fonds sont définitivement perdus.\n" "answer" : "Si vous oubliez votre phrase secrète (seed), il y a des chances que vous l'ayez inscrite quelque part. Vérifiez vos notes et regardez sur votre ordinateur. Si vous ne parvenez pas à la retrouver, il est possible que vous ayez effectué une sauvegarde de Cake Wallet (dans ce cas vous pourrez restaurer d'après cette sauvegarde). Si aucune des ces options ne convient, malheureusement il n'y a plus rien à faire, vos fonds sont définitivement perdus.\n"
}, },
{ {
"question" : "Collectez vous des informations à propos de mon wallet ?", "question" : "Collectez vous des informations à propos de mon portefeuille (wallet) ?",
"answer" : "Cake Wallet NE COLLECTE PAS d'informations à propos de votre wallet. Nous sommes respectueux de votre intimité.\n" "answer" : "Cake Wallet NE COLLECTE PAS d'informations à propos de votre portefeuille (wallet). Nous sommes respectueux de votre intimité.\n"
}, },
{ {
"question" : "Est il possible d'annuler une transaction ?", "question" : "Est il possible d'annuler une transaction ?",
@ -37,11 +37,11 @@
}, },
{ {
"question" : "Que sont les sous-adresses, et comment s'en servir ?", "question" : "Que sont les sous-adresses, et comment s'en servir ?",
"answer" : "Une sous-adresse est une adresse unique que vous pouvez générer à tout moment. Les montants envoyés vers cette adresse arrivent toujours dans votre wallet principal, mais la personne qui vous envoie les fonds ne peut pas déterminer votre adresse principale. Les sous-adresses commencent par un 8.\nVous pouvez créer une nouvelle sous-adresse dans l'écran Réception en appuyant sur le + à côté du bouton Sous-Adresses. Entrez un nom pour la sous-adresse et appuyez sur Ajouter. Ensuite appuyez sur le nom de la sous-adresse quand vous souhaitez l'utiliser !\nSi vous êtres paranoïaque, vous devriez créer une nouvelle sous-adresse à chaque fois que vous voulez recevoir des Monero.\n" "answer" : "Une sous-adresse est une adresse unique que vous pouvez générer à tout moment. Les montants envoyés vers cette adresse arrivent toujours dans votre portefeuille (wallet) principal, mais la personne qui vous envoie les fonds ne peut pas déterminer votre adresse principale. Les sous-adresses commencent par un 8.\nVous pouvez créer une nouvelle sous-adresse dans l'écran Réception en appuyant sur le + à côté du bouton Sous-Adresses. Entrez un nom pour la sous-adresse et appuyez sur Ajouter. Ensuite appuyez sur le nom de la sous-adresse quand vous souhaitez l'utiliser !\nSi vous êtres paranoïaque, vous devriez créer une nouvelle sous-adresse à chaque fois que vous voulez recevoir des Monero.\n"
}, },
{ {
"question" : "Qu'est-ce que l'ID de transaction ?", "question" : "Qu'est-ce que l'ID de transaction ?",
"answer" : "Une empreinte (hash) de transaction, ou ID de transaction, est un moyen unique d'identifier une transaction. Chaque transaction a sa propre empreinte. Si vous deve fournir une empreinte de transaction à quelque'un, allez simplement sur l'écran principal du Wallet, appuyez sur la transaction puis appuyez longuement sur la section du haut et sélectionnez Copier.\n" "answer" : "Une empreinte (hash) de transaction, ou ID de transaction, est un moyen unique d'identifier une transaction. Chaque transaction a sa propre empreinte. Si vous deve fournir une empreinte de transaction à quelque'un, allez simplement sur l'écran principal du Portefeuille (Wallet), appuyez sur la transaction puis appuyez longuement sur la section du haut et sélectionnez Copier.\n"
}, },
{ {
"question" : "Je n'ai pas reçu mes XMR ! Que puis-je faire ?", "question" : "Je n'ai pas reçu mes XMR ! Que puis-je faire ?",

BIN
assets/images/ape_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
assets/images/btt_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
assets/images/dcr_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

BIN
assets/images/doge_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
assets/images/firo_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 997 B

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
assets/images/hbar_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
assets/images/husd_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
assets/images/kmd_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

BIN
assets/images/mana_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
assets/images/mkr_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
assets/images/nano_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
assets/images/near_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
assets/images/oxt_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
assets/images/paxg_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

BIN
assets/images/pivx_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
assets/images/rune_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
assets/images/rvn_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

BIN
assets/images/sc_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
assets/images/scrt_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
assets/images/sol_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
assets/images/stx_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
assets/images/uni_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
assets/images/usdc_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
assets/images/xvg_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 6 KiB

BIN
assets/images/zen_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -8,7 +8,7 @@ String addressFromOutput(Uint8List script, bitcoin.NetworkType networkType) {
data: PaymentData(output: script), data: PaymentData(output: script),
network: networkType) network: networkType)
.data .data
.address; .address!;
} catch (_) {} } catch (_) {}
try { try {
@ -16,8 +16,8 @@ String addressFromOutput(Uint8List script, bitcoin.NetworkType networkType) {
data: PaymentData(output: script), data: PaymentData(output: script),
network: networkType) network: networkType)
.data .data
.address; .address!;
} catch(_) {} } catch(_) {}
return null; return '';
} }

View file

@ -2,7 +2,7 @@ import 'dart:convert';
class BitcoinAddressRecord { class BitcoinAddressRecord {
BitcoinAddressRecord(this.address, BitcoinAddressRecord(this.address,
{this.index, this.isHidden = false, bool isUsed = false}) {required this.index, this.isHidden = false, bool isUsed = false})
: _isUsed = isUsed; : _isUsed = isUsed;
factory BitcoinAddressRecord.fromJSON(String jsonSource) { factory BitcoinAddressRecord.fromJSON(String jsonSource) {
@ -11,8 +11,8 @@ class BitcoinAddressRecord {
return BitcoinAddressRecord( return BitcoinAddressRecord(
decoded['address'] as String, decoded['address'] as String,
index: decoded['index'] as int, index: decoded['index'] as int,
isHidden: decoded['isHidden'] as bool ?? false, isHidden: decoded['isHidden'] as bool? ?? false,
isUsed: decoded['isUsed'] as bool ?? false); isUsed: decoded['isUsed'] as bool? ?? false);
} }
@override @override

View file

@ -7,10 +7,10 @@ final bitcoinAmountFormat = NumberFormat()
..maximumFractionDigits = bitcoinAmountLength ..maximumFractionDigits = bitcoinAmountLength
..minimumFractionDigits = 1; ..minimumFractionDigits = 1;
String bitcoinAmountToString({int amount}) => bitcoinAmountFormat.format( String bitcoinAmountToString({required int amount}) => bitcoinAmountFormat.format(
cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider)); cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider));
double bitcoinAmountToDouble({int amount}) => double bitcoinAmountToDouble({required int amount}) =>
cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider); cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider);
int stringDoubleToBitcoinAmount(String amount) { int stringDoubleToBitcoinAmount(String amount) {

View file

@ -106,15 +106,18 @@ Future<String> generateMnemonic(
return result; return result;
} }
Uint8List mnemonicToSeedBytes(String mnemonic, {String prefix = segwit}) { Future<Uint8List> mnemonicToSeedBytes(String mnemonic, {String prefix = segwit}) async {
final pbkdf2 = cryptography.Pbkdf2( final pbkdf2 = cryptography.Pbkdf2(
macAlgorithm: cryptography.Hmac(cryptography.sha512), macAlgorithm: cryptography.Hmac.sha512(),
iterations: 2048, iterations: 2048,
bits: 512); bits: 512);
final text = normalizeText(mnemonic); final text = normalizeText(mnemonic);
// pbkdf2.deriveKey(secretKey: secretKey, nonce: nonce)
return pbkdf2.deriveBitsSync(text.codeUnits, final key = await pbkdf2.deriveKey(
nonce: cryptography.Nonce('electrum'.codeUnits)); secretKey: cryptography.SecretKey(text.codeUnits),
nonce: 'electrum'.codeUnits);
final bytes = await key.extractBytes();
return Uint8List.fromList(bytes);
} }
bool matchesAnyPrefix(String mnemonic) => bool matchesAnyPrefix(String mnemonic) =>

View file

@ -2,9 +2,9 @@ import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
import 'package:cw_core/output_info.dart'; import 'package:cw_core/output_info.dart';
class BitcoinTransactionCredentials { class BitcoinTransactionCredentials {
BitcoinTransactionCredentials(this.outputs, {this.priority, this.feeRate}); BitcoinTransactionCredentials(this.outputs, {required this.priority, this.feeRate});
final List<OutputInfo> outputs; final List<OutputInfo> outputs;
final BitcoinTransactionPriority priority; final BitcoinTransactionPriority? priority;
final int feeRate; final int? feeRate;
} }

View file

@ -2,7 +2,7 @@ import 'package:cw_core/transaction_priority.dart';
//import 'package:cake_wallet/generated/i18n.dart'; //import 'package:cake_wallet/generated/i18n.dart';
class BitcoinTransactionPriority extends TransactionPriority { class BitcoinTransactionPriority extends TransactionPriority {
const BitcoinTransactionPriority({String title, int raw}) const BitcoinTransactionPriority({required String title, required int raw})
: super(title: title, raw: raw); : super(title: title, raw: raw);
static const List<BitcoinTransactionPriority> all = [fast, medium, slow]; static const List<BitcoinTransactionPriority> all = [fast, medium, slow];
@ -13,7 +13,7 @@ class BitcoinTransactionPriority extends TransactionPriority {
static const BitcoinTransactionPriority fast = static const BitcoinTransactionPriority fast =
BitcoinTransactionPriority(title: 'Fast', raw: 2); BitcoinTransactionPriority(title: 'Fast', raw: 2);
static BitcoinTransactionPriority deserialize({int raw}) { static BitcoinTransactionPriority deserialize({required int raw}) {
switch (raw) { switch (raw) {
case 0: case 0:
return slow; return slow;
@ -22,7 +22,7 @@ class BitcoinTransactionPriority extends TransactionPriority {
case 2: case 2:
return fast; return fast;
default: default:
return null; throw Exception('Unexpected token: $raw for BitcoinTransactionPriority deserialize');
} }
} }
@ -53,7 +53,7 @@ class BitcoinTransactionPriority extends TransactionPriority {
} }
class LitecoinTransactionPriority extends BitcoinTransactionPriority { class LitecoinTransactionPriority extends BitcoinTransactionPriority {
const LitecoinTransactionPriority({String title, int raw}) const LitecoinTransactionPriority({required String title, required int raw})
: super(title: title, raw: raw); : super(title: title, raw: raw);
static const List<LitecoinTransactionPriority> all = [fast, medium, slow]; static const List<LitecoinTransactionPriority> all = [fast, medium, slow];
@ -64,7 +64,7 @@ class LitecoinTransactionPriority extends BitcoinTransactionPriority {
static const LitecoinTransactionPriority fast = static const LitecoinTransactionPriority fast =
LitecoinTransactionPriority(title: 'Fast', raw: 2); LitecoinTransactionPriority(title: 'Fast', raw: 2);
static LitecoinTransactionPriority deserialize({int raw}) { static LitecoinTransactionPriority deserialize({required int raw}) {
switch (raw) { switch (raw) {
case 0: case 0:
return slow; return slow;
@ -73,7 +73,7 @@ class LitecoinTransactionPriority extends BitcoinTransactionPriority {
case 2: case 2:
return fast; return fast;
default: default:
return null; throw Exception('Unexpected token: $raw for LitecoinTransactionPriority deserialize');
} }
} }

View file

@ -1,4 +1,5 @@
import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; import 'package:cw_bitcoin/bitcoin_mnemonic.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:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
@ -17,12 +18,13 @@ class BitcoinWallet = BitcoinWalletBase with _$BitcoinWallet;
abstract class BitcoinWalletBase extends ElectrumWallet with Store { abstract class BitcoinWalletBase extends ElectrumWallet with Store {
BitcoinWalletBase( BitcoinWalletBase(
{@required String mnemonic, {required String mnemonic,
@required String password, required String password,
@required WalletInfo walletInfo, required WalletInfo walletInfo,
@required Box<UnspentCoinsInfo> unspentCoinsInfo, required Box<UnspentCoinsInfo> unspentCoinsInfo,
List<BitcoinAddressRecord> initialAddresses, required Uint8List seedBytes,
ElectrumBalance initialBalance, List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0, int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0}) int initialChangeAddressIndex = 0})
: super( : super(
@ -32,7 +34,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
unspentCoinsInfo: unspentCoinsInfo, unspentCoinsInfo: unspentCoinsInfo,
networkType: bitcoin.bitcoin, networkType: bitcoin.bitcoin,
initialAddresses: initialAddresses, initialAddresses: initialAddresses,
initialBalance: initialBalance) { initialBalance: initialBalance,
seedBytes: seedBytes,
currency: CryptoCurrency.btc) {
walletAddresses = BitcoinWalletAddresses( walletAddresses = BitcoinWalletAddresses(
walletInfo, walletInfo,
electrumClient: electrumClient, electrumClient: electrumClient,
@ -40,20 +44,40 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
initialRegularAddressIndex: initialRegularAddressIndex, initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex, initialChangeAddressIndex: initialChangeAddressIndex,
mainHd: hd, mainHd: hd,
sideHd: bitcoin.HDWallet.fromSeed( sideHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType)
mnemonicToSeedBytes(mnemonic), network: networkType)
.derivePath("m/0'/1"), .derivePath("m/0'/1"),
networkType: networkType); networkType: networkType);
} }
static Future<BitcoinWallet> open({ static Future<BitcoinWallet> create({
@required String name, required String mnemonic,
@required WalletInfo walletInfo, required String password,
@required Box<UnspentCoinsInfo> unspentCoinsInfo, required WalletInfo walletInfo,
@required String password, required Box<UnspentCoinsInfo> unspentCoinsInfo,
List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0
}) async { }) async {
final snp = ElectrumWallletSnapshot(name, walletInfo.type, password); return BitcoinWallet(
await snp.load(); mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
seedBytes: await mnemonicToSeedBytes(mnemonic),
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex);
}
static Future<BitcoinWallet> open({
required String name,
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required String password,
}) async {
final snp = await ElectrumWallletSnapshot.load(name, walletInfo.type, password);
return BitcoinWallet( return BitcoinWallet(
mnemonic: snp.mnemonic, mnemonic: snp.mnemonic,
password: password, password: password,
@ -61,6 +85,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
unspentCoinsInfo: unspentCoinsInfo, unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp.addresses, initialAddresses: snp.addresses,
initialBalance: snp.balance, initialBalance: snp.balance,
seedBytes: await mnemonicToSeedBytes(snp.mnemonic),
initialRegularAddressIndex: snp.regularAddressIndex, initialRegularAddressIndex: snp.regularAddressIndex,
initialChangeAddressIndex: snp.changeAddressIndex); initialChangeAddressIndex: snp.changeAddressIndex);
} }

View file

@ -16,13 +16,13 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses
with Store { with Store {
BitcoinWalletAddressesBase( BitcoinWalletAddressesBase(
WalletInfo walletInfo, WalletInfo walletInfo,
{@required List<BitcoinAddressRecord> initialAddresses, {required bitcoin.HDWallet mainHd,
required bitcoin.HDWallet sideHd,
required bitcoin.NetworkType networkType,
required ElectrumClient electrumClient,
List<BitcoinAddressRecord>? initialAddresses,
int initialRegularAddressIndex = 0, int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0, int initialChangeAddressIndex = 0})
ElectrumClient electrumClient,
@required bitcoin.HDWallet mainHd,
@required bitcoin.HDWallet sideHd,
@required bitcoin.NetworkType networkType})
: super( : super(
walletInfo, walletInfo,
initialAddresses: initialAddresses, initialAddresses: initialAddresses,
@ -34,6 +34,6 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses
networkType: networkType); networkType: networkType);
@override @override
String getAddress({@required int index, @required bitcoin.HDWallet hd}) => String getAddress({required int index, required bitcoin.HDWallet hd}) =>
generateP2WPKHAddress(hd: hd, index: index, networkType: networkType); generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
} }

View file

@ -2,13 +2,13 @@ import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
class BitcoinNewWalletCredentials extends WalletCredentials { class BitcoinNewWalletCredentials extends WalletCredentials {
BitcoinNewWalletCredentials({String name, WalletInfo walletInfo}) BitcoinNewWalletCredentials({required String name, WalletInfo? walletInfo})
: super(name: name, walletInfo: walletInfo); : super(name: name, walletInfo: walletInfo);
} }
class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials { class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials {
BitcoinRestoreWalletFromSeedCredentials( BitcoinRestoreWalletFromSeedCredentials(
{String name, String password, this.mnemonic, WalletInfo walletInfo}) {required String name, required String password, required this.mnemonic, WalletInfo? walletInfo})
: super(name: name, password: password, walletInfo: walletInfo); : super(name: name, password: password, walletInfo: walletInfo);
final String mnemonic; final String mnemonic;
@ -16,7 +16,7 @@ class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials {
class BitcoinRestoreWalletFromWIFCredentials extends WalletCredentials { class BitcoinRestoreWalletFromWIFCredentials extends WalletCredentials {
BitcoinRestoreWalletFromWIFCredentials( BitcoinRestoreWalletFromWIFCredentials(
{String name, String password, this.wif, WalletInfo walletInfo}) {required String name, required String password, required this.wif, WalletInfo? walletInfo})
: super(name: name, password: password, walletInfo: walletInfo); : super(name: name, password: password, walletInfo: walletInfo);
final String wif; final String wif;

View file

@ -1,7 +1,5 @@
import 'package:flutter/foundation.dart';
class BitcoinWalletKeys { class BitcoinWalletKeys {
const BitcoinWalletKeys({@required this.wif, @required this.privateKey, @required this.publicKey}); const BitcoinWalletKeys({required this.wif, required this.privateKey, required this.publicKey});
final String wif; final String wif;
final String privateKey; final String privateKey;

View file

@ -10,6 +10,7 @@ import 'package:cw_core/pathForWallet.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';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:collection/collection.dart';
class BitcoinWalletService extends WalletService< class BitcoinWalletService extends WalletService<
BitcoinNewWalletCredentials, BitcoinNewWalletCredentials,
@ -25,10 +26,10 @@ class BitcoinWalletService extends WalletService<
@override @override
Future<BitcoinWallet> create(BitcoinNewWalletCredentials credentials) async { Future<BitcoinWallet> create(BitcoinNewWalletCredentials credentials) async {
final wallet = BitcoinWallet( final wallet = await BitcoinWalletBase.create(
mnemonic: await generateMnemonic(), mnemonic: await generateMnemonic(),
password: credentials.password, password: credentials.password!,
walletInfo: credentials.walletInfo, walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource); unspentCoinsInfo: unspentCoinsInfoSource);
await wallet.save(); await wallet.save();
await wallet.init(); await wallet.init();
@ -41,9 +42,8 @@ class BitcoinWalletService extends WalletService<
@override @override
Future<BitcoinWallet> openWallet(String name, String password) async { Future<BitcoinWallet> openWallet(String name, String password) async {
final walletInfo = walletInfoSource.values.firstWhere( final walletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(name, getType()), (info) => info.id == WalletBase.idFor(name, getType()))!;
orElse: () => null);
final wallet = await BitcoinWalletBase.open( final wallet = await BitcoinWalletBase.open(
password: password, name: name, walletInfo: walletInfo, password: password, name: name, walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource); unspentCoinsInfo: unspentCoinsInfoSource);
@ -68,10 +68,10 @@ class BitcoinWalletService extends WalletService<
throw BitcoinMnemonicIsIncorrectException(); throw BitcoinMnemonicIsIncorrectException();
} }
final wallet = BitcoinWallet( final wallet = await BitcoinWalletBase.create(
password: credentials.password, password: credentials.password!,
mnemonic: credentials.mnemonic, mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo, walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource); unspentCoinsInfo: unspentCoinsInfoSource);
await wallet.save(); await wallet.save();
await wallet.init(); await wallet.init();

View file

@ -7,6 +7,7 @@ import 'package:cw_bitcoin/bitcoin_amount_format.dart';
import 'package:cw_bitcoin/script_hash.dart'; import 'package:cw_bitcoin/script_hash.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
import 'package:collection/collection.dart';
String jsonrpcparams(List<Object> params) { String jsonrpcparams(List<Object> params) {
final _params = params?.map((val) => '"${val.toString()}"')?.join(','); final _params = params?.map((val) => '"${val.toString()}"')?.join(',');
@ -14,14 +15,20 @@ String jsonrpcparams(List<Object> params) {
} }
String jsonrpc( String jsonrpc(
{String method, List<Object> params, int id, double version = 2.0}) => {required String method,
required List<Object> params,
required int id,
double version = 2.0}) =>
'{"jsonrpc": "$version", "method": "$method", "id": "$id", "params": ${json.encode(params)}}\n'; '{"jsonrpc": "$version", "method": "$method", "id": "$id", "params": ${json.encode(params)}}\n';
class SocketTask { class SocketTask {
SocketTask({this.completer, this.isSubscription, this.subject}); SocketTask({
required this.isSubscription,
this.completer,
this.subject});
final Completer completer; final Completer<dynamic>? completer;
final BehaviorSubject subject; final BehaviorSubject<dynamic>? subject;
final bool isSubscription; final bool isSubscription;
} }
@ -36,18 +43,18 @@ class ElectrumClient {
static const aliveTimerDuration = Duration(seconds: 2); static const aliveTimerDuration = Duration(seconds: 2);
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;
bool _isConnected; bool _isConnected;
Timer _aliveTimer; Timer? _aliveTimer;
String unterminatedString; String unterminatedString;
Future<void> connectToUri(Uri uri) async => Future<void> connectToUri(Uri uri) async =>
await connect(host: uri.host, port: uri.port); await connect(host: uri.host, port: uri.port);
Future<void> connect({@required String host, @required int port}) async { Future<void> connect({required String host, required int port}) async {
try { try {
await socket?.close(); await socket?.close();
} catch (_) {} } catch (_) {}
@ -56,10 +63,11 @@ class ElectrumClient {
timeout: connectionTimeout, onBadCertificate: (_) => true); timeout: connectionTimeout, onBadCertificate: (_) => true);
_setIsConnected(true); _setIsConnected(true);
socket.listen((Uint8List event) { socket!.listen((Uint8List event) {
try { try {
final msg = utf8.decode(event.toList());
final response = final response =
json.decode(utf8.decode(event.toList())) as Map<String, Object>; json.decode(msg) as Map<String, dynamic>;
_handleResponse(response); _handleResponse(response);
} on FormatException catch (e) { } on FormatException catch (e) {
final msg = e.message.toLowerCase(); final msg = e.message.toLowerCase();
@ -75,12 +83,12 @@ class ElectrumClient {
if (isJSONStringCorrect(unterminatedString)) { if (isJSONStringCorrect(unterminatedString)) {
final response = final response =
json.decode(unterminatedString) as Map<String, Object>; json.decode(unterminatedString) as Map<String, dynamic>;
_handleResponse(response); _handleResponse(response);
unterminatedString = ''; unterminatedString = '';
} }
} on TypeError catch (e) { } on TypeError catch (e) {
if (!e.toString().contains('Map<String, Object>')) { if (!e.toString().contains('Map<String, Object>') || !e.toString().contains('Map<String, dynamic>')) {
return; return;
} }
@ -89,9 +97,10 @@ class ElectrumClient {
if (isJSONStringCorrect(unterminatedString)) { if (isJSONStringCorrect(unterminatedString)) {
final response = final response =
json.decode(unterminatedString) as Map<String, Object>; json.decode(unterminatedString) as Map<String, dynamic>;
_handleResponse(response); _handleResponse(response);
unterminatedString = null; // unterminatedString = null;
unterminatedString = '';
} }
} catch (e) { } catch (e) {
print(e.toString()); print(e.toString());
@ -128,14 +137,14 @@ class ElectrumClient {
return []; return [];
}); });
Future<Map<String, Object>> getBalance(String scriptHash) => Future<Map<String, dynamic>> getBalance(String scriptHash) =>
call(method: 'blockchain.scripthash.get_balance', params: [scriptHash]) call(method: 'blockchain.scripthash.get_balance', params: [scriptHash])
.then((dynamic result) { .then((dynamic result) {
if (result is Map<String, Object>) { if (result is Map<String, dynamic>) {
return result; return result;
} }
return <String, Object>{}; return <String, dynamic>{};
}); });
Future<List<Map<String, dynamic>>> getHistory(String scriptHash) => Future<List<Map<String, dynamic>>> getHistory(String scriptHash) =>
@ -143,11 +152,11 @@ class ElectrumClient {
.then((dynamic result) { .then((dynamic result) {
if (result is List) { if (result is List) {
return result.map((dynamic val) { return result.map((dynamic val) {
if (val is Map<String, Object>) { if (val is Map<String, dynamic>) {
return val; return val;
} }
return <String, Object>{}; return <String, dynamic>{};
}).toList(); }).toList();
} }
@ -162,12 +171,12 @@ class ElectrumClient {
.then((dynamic result) { .then((dynamic result) {
if (result is List) { if (result is List) {
return result.map((dynamic val) { return result.map((dynamic val) {
if (val is Map<String, Object>) { if (val is Map<String, dynamic>) {
val['address'] = address; val['address'] = address;
return val; return val;
} }
return <String, Object>{}; return <String, dynamic>{};
}).toList(); }).toList();
} }
@ -179,11 +188,11 @@ class ElectrumClient {
.then((dynamic result) { .then((dynamic result) {
if (result is List) { if (result is List) {
return result.map((dynamic val) { return result.map((dynamic val) {
if (val is Map<String, Object>) { if (val is Map<String, dynamic>) {
return val; return val;
} }
return <String, Object>{}; return <String, dynamic>{};
}).toList(); }).toList();
} }
@ -195,30 +204,30 @@ class ElectrumClient {
.then((dynamic result) { .then((dynamic result) {
if (result is List) { if (result is List) {
return result.map((dynamic val) { return result.map((dynamic val) {
if (val is Map<String, Object>) { if (val is Map<String, dynamic>) {
return val; return val;
} }
return <String, Object>{}; return <String, dynamic>{};
}).toList(); }).toList();
} }
return []; return [];
}); });
Future<Map<String, Object>> getTransactionRaw( Future<Map<String, dynamic>> getTransactionRaw(
{@required String hash}) async => {required String hash}) async =>
call(method: 'blockchain.transaction.get', params: [hash, true]) call(method: 'blockchain.transaction.get', params: [hash, true])
.then((dynamic result) { .then((dynamic result) {
if (result is Map<String, Object>) { if (result is Map<String, dynamic>) {
return result; return result;
} }
return <String, Object>{}; return <String, dynamic>{};
}); });
Future<String> getTransactionHex( Future<String> getTransactionHex(
{@required String hash}) async => {required String hash}) async =>
call(method: 'blockchain.transaction.get', params: [hash, false]) call(method: 'blockchain.transaction.get', params: [hash, false])
.then((dynamic result) { .then((dynamic result) {
if (result is String) { if (result is String) {
@ -229,7 +238,7 @@ class ElectrumClient {
}); });
Future<String> broadcastTransaction( Future<String> broadcastTransaction(
{@required String transactionRaw}) async => {required String transactionRaw}) async =>
call(method: 'blockchain.transaction.broadcast', params: [transactionRaw]) call(method: 'blockchain.transaction.broadcast', params: [transactionRaw])
.then((dynamic result) { .then((dynamic result) {
if (result is String) { if (result is String) {
@ -240,16 +249,16 @@ class ElectrumClient {
}); });
Future<Map<String, dynamic>> getMerkle( Future<Map<String, dynamic>> getMerkle(
{@required String hash, @required int height}) async => {required String hash, required int height}) async =>
await call( await call(
method: 'blockchain.transaction.get_merkle', method: 'blockchain.transaction.get_merkle',
params: [hash, height]) as Map<String, dynamic>; params: [hash, height]) as Map<String, dynamic>;
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]) await call(method: 'blockchain.block.get_header', params: [height])
as Map<String, dynamic>; as Map<String, dynamic>;
Future<double> estimatefee({@required int p}) => Future<double> estimatefee({required int p}) =>
call(method: 'blockchain.estimatefee', params: [p]) call(method: 'blockchain.estimatefee', params: [p])
.then((dynamic result) { .then((dynamic result) {
if (result is double) { if (result is double) {
@ -266,13 +275,26 @@ class ElectrumClient {
Future<List<List<int>>> feeHistogram() => Future<List<List<int>>> feeHistogram() =>
call(method: 'mempool.get_fee_histogram').then((dynamic result) { call(method: 'mempool.get_fee_histogram').then((dynamic result) {
if (result is List) { if (result is List) {
return result.map((dynamic e) { // return result.map((dynamic e) {
if (e is List) { // if (e is List) {
return e.map((dynamic ee) => ee is int ? ee : null).toList(); // return e.map((dynamic ee) => ee is int ? ee : null).toList();
} // }
return null; // return null;
}).toList(); // }).toList();
final histogram = <List<int>>[];
for (final e in result) {
if (e is List) {
final eee = <int>[];
for (final ee in e) {
if (ee is int) {
eee.add(ee);
}
}
histogram.add(eee);
}
}
return histogram;
} }
return []; return [];
@ -299,7 +321,7 @@ class ElectrumClient {
} }
} }
BehaviorSubject<Object> scripthashUpdate(String scripthash) { BehaviorSubject<Object>? scripthashUpdate(String scripthash) {
_id += 1; _id += 1;
return subscribe<Object>( return subscribe<Object>(
id: 'blockchain.scripthash.subscribe:$scripthash', id: 'blockchain.scripthash.subscribe:$scripthash',
@ -307,14 +329,14 @@ class ElectrumClient {
params: [scripthash]); params: [scripthash]);
} }
BehaviorSubject<T> subscribe<T>( BehaviorSubject<T>? subscribe<T>(
{@required String id, {required String id,
@required String method, required String method,
List<Object> params = const []}) { List<Object> params = const []}) {
try { try {
final subscription = BehaviorSubject<T>(); final subscription = BehaviorSubject<T>();
_regisrySubscription(id, subscription); _regisrySubscription(id, subscription);
socket.write(jsonrpc(method: method, id: _id, params: params)); socket!.write(jsonrpc(method: method, id: _id, params: params));
return subscription; return subscription;
} catch(e) { } catch(e) {
@ -323,18 +345,18 @@ class ElectrumClient {
} }
} }
Future<dynamic> call({String method, List<Object> params = const []}) async { Future<dynamic> call({required String method, List<Object> params = const []}) async {
final completer = Completer<dynamic>(); final completer = Completer<dynamic>();
_id += 1; _id += 1;
final id = _id; final id = _id;
_registryTask(id, completer); _registryTask(id, completer);
socket.write(jsonrpc(method: method, id: id, params: params)); socket!.write(jsonrpc(method: method, id: id, params: params));
return completer.future; return completer.future;
} }
Future<dynamic> callWithTimeout( Future<dynamic> callWithTimeout(
{String method, {required String method,
List<Object> params = const [], List<Object> params = const [],
int timeout = 2000}) async { int timeout = 2000}) async {
try { try {
@ -342,7 +364,7 @@ class ElectrumClient {
_id += 1; _id += 1;
final id = _id; final id = _id;
_registryTask(id, completer); _registryTask(id, completer);
socket.write(jsonrpc(method: method, id: id, params: params)); socket!.write(jsonrpc(method: method, id: id, params: params));
Timer(Duration(milliseconds: timeout), () { Timer(Duration(milliseconds: timeout), () {
if (!completer.isCompleted) { if (!completer.isCompleted) {
completer.completeError(RequestFailedTimeoutException(method, id)); completer.completeError(RequestFailedTimeoutException(method, id));
@ -356,35 +378,35 @@ class ElectrumClient {
} }
Future<void> close() async { Future<void> close() async {
_aliveTimer.cancel(); _aliveTimer?.cancel();
await socket.close(); await socket?.close();
onConnectionStatusChange = null; onConnectionStatusChange = null;
} }
void _registryTask(int id, Completer completer) => _tasks[id.toString()] = void _registryTask(int id, Completer<dynamic> completer) => _tasks[id.toString()] =
SocketTask(completer: completer, isSubscription: false); SocketTask(completer: completer, isSubscription: false);
void _regisrySubscription(String id, BehaviorSubject subject) => void _regisrySubscription(String id, BehaviorSubject<dynamic> subject) =>
_tasks[id] = SocketTask(subject: subject, isSubscription: true); _tasks[id] = SocketTask(subject: subject, isSubscription: true);
void _finish(String id, Object data) { void _finish(String id, Object? data) {
if (_tasks[id] == null) { if (_tasks[id] == null) {
return; return;
} }
if (!(_tasks[id]?.completer?.isCompleted ?? false)) { if (!(_tasks[id]?.completer?.isCompleted ?? false)) {
_tasks[id]?.completer?.complete(data); _tasks[id]?.completer!.complete(data);
} }
if (!(_tasks[id]?.isSubscription ?? false)) { if (!(_tasks[id]?.isSubscription ?? false)) {
_tasks[id] = null; _tasks.remove(id);
} else { } else {
_tasks[id].subject.add(data); _tasks[id]?.subject?.add(data);
} }
} }
void _methodHandler( void _methodHandler(
{@required String method, @required Map<String, Object> request}) { {required String method, required Map<String, dynamic> request}) {
switch (method) { switch (method) {
case 'blockchain.scripthash.subscribe': case 'blockchain.scripthash.subscribe':
final params = request['params'] as List<dynamic>; final params = request['params'] as List<dynamic>;
@ -406,7 +428,7 @@ class ElectrumClient {
_isConnected = isConnected; _isConnected = isConnected;
} }
void _handleResponse(Map<String, Object> response) { void _handleResponse(Map<String, dynamic> response) {
final method = response['method']; final method = response['method'];
final id = response['id'] as String; final id = response['id'] as String;
final result = response['result']; final result = response['result'];

View file

@ -4,10 +4,10 @@ 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}) const ElectrumBalance({required this.confirmed, required this.unconfirmed})
: super(confirmed, unconfirmed); : super(confirmed, unconfirmed);
factory ElectrumBalance.fromJSON(String jsonSource) { static ElectrumBalance? fromJSON(String? jsonSource) {
if (jsonSource == null) { if (jsonSource == null) {
return null; return null;
} }
@ -15,8 +15,8 @@ class ElectrumBalance extends Balance {
final decoded = json.decode(jsonSource) as Map; final decoded = json.decode(jsonSource) as Map;
return ElectrumBalance( return ElectrumBalance(
confirmed: decoded['confirmed'] as int ?? 0, confirmed: decoded['confirmed'] as int? ?? 0,
unconfirmed: decoded['unconfirmed'] as int ?? 0); unconfirmed: decoded['unconfirmed'] as int? ?? 0);
} }
final int confirmed; final int confirmed;

View file

@ -17,7 +17,7 @@ class ElectrumTransactionHistory = ElectrumTransactionHistoryBase
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>();
@ -56,18 +56,18 @@ abstract class ElectrumTransactionHistoryBase
await save(); await save();
} }
Future<Map<String, Object>> _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, Object>; return json.decode(content) as Map<String, dynamic>;
} }
Future<void> _load() async { Future<void> _load() async {
try { try {
final content = await _read(); final content = await _read();
final txs = content['transactions'] as Map<String, Object> ?? {}; final txs = content['transactions'] as Map<String, dynamic> ?? {};
txs.entries.forEach((entry) { txs.entries.forEach((entry) {
final val = entry.value; final val = entry.value;
@ -93,11 +93,11 @@ abstract class ElectrumTransactionHistoryBase
transactions[transaction.id] = transaction; transactions[transaction.id] = transaction;
} else { } else {
final originalTx = transactions[transaction.id]; final originalTx = transactions[transaction.id];
originalTx.confirmations = transaction.confirmations; originalTx?.confirmations = transaction.confirmations;
originalTx.amount = transaction.amount; originalTx?.amount = transaction.amount;
originalTx.height = transaction.height; originalTx?.height = transaction.height;
originalTx.date ??= transaction.date; originalTx?.date ??= transaction.date;
originalTx.isPending = transaction.isPending; originalTx?.isPending = transaction.isPending;
} }
} }
} }

View file

@ -10,23 +10,26 @@ import 'package:cw_core/format_amount.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
class ElectrumTransactionBundle { class ElectrumTransactionBundle {
ElectrumTransactionBundle(this.originalTransaction, {this.ins, this.time, this.confirmations}); ElectrumTransactionBundle(this.originalTransaction,
{required this.ins,
required this.confirmations,
this.time});
final bitcoin.Transaction originalTransaction; final bitcoin.Transaction originalTransaction;
final List<bitcoin.Transaction> ins; final List<bitcoin.Transaction> ins;
final int time; final int? time;
final int confirmations; final int confirmations;
} }
class ElectrumTransactionInfo extends TransactionInfo { class ElectrumTransactionInfo extends TransactionInfo {
ElectrumTransactionInfo(this.type, ElectrumTransactionInfo(this.type,
{@required String id, {required String id,
@required int height, required int height,
@required int amount, required int amount,
@required int fee, int? fee,
@required TransactionDirection direction, required TransactionDirection direction,
@required bool isPending, required bool isPending,
@required DateTime date, required DateTime date,
@required int confirmations}) { required int confirmations}) {
this.id = id; this.id = id;
this.height = height; this.height = height;
this.amount = amount; this.amount = amount;
@ -39,15 +42,15 @@ class ElectrumTransactionInfo extends TransactionInfo {
factory ElectrumTransactionInfo.fromElectrumVerbose( factory ElectrumTransactionInfo.fromElectrumVerbose(
Map<String, Object> obj, WalletType type, Map<String, Object> obj, WalletType type,
{@required List<BitcoinAddressRecord> addresses, @required int height}) { {required List<BitcoinAddressRecord> addresses, required int height}) {
final addressesSet = addresses.map((addr) => addr.address).toSet(); final addressesSet = addresses.map((addr) => addr.address).toSet();
final id = obj['txid'] as String; final id = obj['txid'] as String;
final vins = obj['vin'] as List<Object> ?? []; final vins = obj['vin'] as List<Object>? ?? [];
final vout = (obj['vout'] as List<Object> ?? []); final vout = (obj['vout'] as List<Object>? ?? []);
final date = obj['time'] is int final date = obj['time'] is int
? DateTime.fromMillisecondsSinceEpoch((obj['time'] as int) * 1000) ? DateTime.fromMillisecondsSinceEpoch((obj['time'] as int) * 1000)
: DateTime.now(); : DateTime.now();
final confirmations = obj['confirmations'] as int ?? 0; final confirmations = obj['confirmations'] as int? ?? 0;
var direction = TransactionDirection.incoming; var direction = TransactionDirection.incoming;
var inputsAmount = 0; var inputsAmount = 0;
var amount = 0; var amount = 0;
@ -57,21 +60,21 @@ class ElectrumTransactionInfo extends TransactionInfo {
final vout = vin['vout'] as int; final vout = vin['vout'] as int;
final out = vin['tx']['vout'][vout] as Map; final out = vin['tx']['vout'][vout] as Map;
final outAddresses = final outAddresses =
(out['scriptPubKey']['addresses'] as List<Object>)?.toSet(); (out['scriptPubKey']['addresses'] as List<Object>?)?.toSet();
inputsAmount += inputsAmount +=
stringDoubleToBitcoinAmount((out['value'] as double ?? 0).toString()); stringDoubleToBitcoinAmount((out['value'] as double? ?? 0).toString());
if (outAddresses?.intersection(addressesSet)?.isNotEmpty ?? false) { if (outAddresses?.intersection(addressesSet).isNotEmpty ?? false) {
direction = TransactionDirection.outgoing; direction = TransactionDirection.outgoing;
} }
} }
for (dynamic out in vout) { for (dynamic out in vout) {
final outAddresses = final outAddresses =
out['scriptPubKey']['addresses'] as List<Object> ?? []; out['scriptPubKey']['addresses'] as List<Object>? ?? [];
final ntrs = outAddresses.toSet().intersection(addressesSet); final ntrs = outAddresses.toSet().intersection(addressesSet);
final value = stringDoubleToBitcoinAmount( final value = stringDoubleToBitcoinAmount(
(out['value'] as double ?? 0.0).toString()); (out['value'] as double? ?? 0.0).toString());
totalOutAmount += value; totalOutAmount += value;
if ((direction == TransactionDirection.incoming && ntrs.isNotEmpty) || if ((direction == TransactionDirection.incoming && ntrs.isNotEmpty) ||
@ -97,10 +100,10 @@ class ElectrumTransactionInfo extends TransactionInfo {
ElectrumTransactionBundle bundle, ElectrumTransactionBundle bundle,
WalletType type, WalletType type,
bitcoin.NetworkType networkType, bitcoin.NetworkType networkType,
{@required Set<String> addresses, {required Set<String> addresses,
int height}) { required int height}) {
final date = bundle.time != null final date = bundle.time != null
? DateTime.fromMillisecondsSinceEpoch(bundle.time * 1000) ? DateTime.fromMillisecondsSinceEpoch(bundle.time! * 1000)
: DateTime.now(); : DateTime.now();
var direction = TransactionDirection.incoming; var direction = TransactionDirection.incoming;
var amount = 0; var amount = 0;
@ -111,21 +114,21 @@ class ElectrumTransactionInfo extends TransactionInfo {
final input = bundle.originalTransaction.ins[i]; final input = bundle.originalTransaction.ins[i];
final inputTransaction = bundle.ins[i]; final inputTransaction = bundle.ins[i];
final vout = input.index; final vout = input.index;
final outTransaction = inputTransaction.outs[vout]; final outTransaction = inputTransaction.outs[vout!];
final address = addressFromOutput(outTransaction.script, networkType); final address = addressFromOutput(outTransaction.script!, networkType);
inputAmount += outTransaction.value; inputAmount += outTransaction.value!;
if (addresses.contains(address)) { if (addresses.contains(address)) {
direction = TransactionDirection.outgoing; direction = TransactionDirection.outgoing;
} }
} }
for (final out in bundle.originalTransaction.outs) { for (final out in bundle.originalTransaction.outs) {
totalOutAmount += out.value; totalOutAmount += out.value!;
final address = addressFromOutput(out.script, networkType); final address = addressFromOutput(out.script!, networkType);
final addressExists = addresses.contains(address); final addressExists = addresses.contains(address);
if ((direction == TransactionDirection.incoming && addressExists) || if ((direction == TransactionDirection.incoming && addressExists) ||
(direction == TransactionDirection.outgoing && !addressExists)) { (direction == TransactionDirection.outgoing && !addressExists)) {
amount += out.value; amount += out.value!;
} }
} }
@ -142,7 +145,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
} }
factory ElectrumTransactionInfo.fromHexAndHeader(WalletType type, String hex, factory ElectrumTransactionInfo.fromHexAndHeader(WalletType type, String hex,
{List<String> addresses, int height, int timestamp, int confirmations}) { {List<String>? addresses, required int height, int? timestamp, required int confirmations}) {
final tx = bitcoin.Transaction.fromHex(hex); final tx = bitcoin.Transaction.fromHex(hex);
var exist = false; var exist = false;
var amount = 0; var amount = 0;
@ -155,7 +158,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
exist = addresses.contains(p2pkh.data.address); exist = addresses.contains(p2pkh.data.address);
if (exist) { if (exist) {
amount += out.value; amount += out.value!;
} }
} catch (_) {} } catch (_) {}
}); });
@ -191,15 +194,15 @@ class ElectrumTransactionInfo extends TransactionInfo {
final WalletType type; final WalletType type;
String _fiatAmount; String? _fiatAmount;
@override @override
String amountFormatted() => String amountFormatted() =>
'${formatAmount(bitcoinAmountToString(amount: amount))} ${walletTypeToCryptoCurrency(type).title}'; '${formatAmount(bitcoinAmountToString(amount: amount))} ${walletTypeToCryptoCurrency(type).title}';
@override @override
String feeFormatted() => fee != null String? feeFormatted() => fee != null
? '${formatAmount(bitcoinAmountToString(amount: fee))} ${walletTypeToCryptoCurrency(type).title}' ? '${formatAmount(bitcoinAmountToString(amount: fee!))} ${walletTypeToCryptoCurrency(type).title}'
: ''; : '';
@override @override
@ -225,7 +228,9 @@ class ElectrumTransactionInfo extends TransactionInfo {
m['id'] = id; m['id'] = id;
m['height'] = height; m['height'] = height;
m['amount'] = amount; m['amount'] = amount;
m['direction'] = direction.index; // FIX-ME: Hardcoded value
// m['direction'] = direction.index;
m['direction'] = 0;
m['date'] = date.millisecondsSinceEpoch; m['date'] = date.millisecondsSinceEpoch;
m['isPending'] = isPending; m['isPending'] = isPending;
m['confirmations'] = confirmations; m['confirmations'] = confirmations;

View file

@ -34,6 +34,7 @@ import 'package:cw_core/wallet_info.dart';
import 'package:cw_bitcoin/electrum.dart'; import 'package:cw_bitcoin/electrum.dart';
import 'package:hex/hex.dart'; import 'package:hex/hex.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:collection/collection.dart';
part 'electrum_wallet.g.dart'; part 'electrum_wallet.g.dart';
@ -42,31 +43,34 @@ class ElectrumWallet = ElectrumWalletBase with _$ElectrumWallet;
abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance, abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
ElectrumTransactionHistory, ElectrumTransactionInfo> with Store { ElectrumTransactionHistory, ElectrumTransactionInfo> with Store {
ElectrumWalletBase( ElectrumWalletBase(
{@required String password, {required String password,
@required WalletInfo walletInfo, required WalletInfo walletInfo,
@required Box<UnspentCoinsInfo> unspentCoinsInfo, required Box<UnspentCoinsInfo> unspentCoinsInfo,
@required List<BitcoinAddressRecord> initialAddresses, required this.networkType,
@required this.networkType, required this.mnemonic,
@required this.mnemonic, required Uint8List seedBytes,
ElectrumClient electrumClient, List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance initialBalance}) ElectrumClient? electrumClient,
: hd = bitcoin.HDWallet.fromSeed(mnemonicToSeedBytes(mnemonic), ElectrumBalance? initialBalance,
network: networkType) CryptoCurrency? currency})
: hd = bitcoin.HDWallet.fromSeed(seedBytes, network: networkType)
.derivePath("m/0'/0"), .derivePath("m/0'/0"),
syncStatus = NotConnectedSyncStatus(), syncStatus = NotConnectedSyncStatus(),
_password = password, _password = password,
_feeRates = <int>[], _feeRates = <int>[],
_isTransactionUpdating = false, _isTransactionUpdating = false,
unspentCoins = [],
_scripthashesUpdateSubject = {},
balance = ObservableMap<CryptoCurrency, ElectrumBalance>.of(
currency != null
? {currency: initialBalance ?? const ElectrumBalance(confirmed: 0, unconfirmed: 0)}
: {}),
this.unspentCoinsInfo = unspentCoinsInfo,
super(walletInfo) { super(walletInfo) {
balance = ObservableMap<CryptoCurrency, ElectrumBalance>.of({
currency: initialBalance ?? const ElectrumBalance(confirmed: 0, unconfirmed: 0)});
this.electrumClient = electrumClient ?? ElectrumClient(); this.electrumClient = electrumClient ?? ElectrumClient();
this.walletInfo = walletInfo; this.walletInfo = walletInfo;
this.unspentCoinsInfo = unspentCoinsInfo;
transactionHistory = transactionHistory =
ElectrumTransactionHistory(walletInfo: walletInfo, password: password); ElectrumTransactionHistory(walletInfo: walletInfo, password: password);
unspentCoins = [];
_scripthashesUpdateSubject = {};
} }
static int estimatedTransactionSize(int inputsCount, int outputsCounts) => static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
@ -75,15 +79,15 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
final bitcoin.HDWallet hd; final bitcoin.HDWallet hd;
final String mnemonic; final String mnemonic;
ElectrumClient electrumClient; late ElectrumClient electrumClient;
Box<UnspentCoinsInfo> unspentCoinsInfo; Box<UnspentCoinsInfo> unspentCoinsInfo;
@override @override
ElectrumWalletAddresses walletAddresses; late ElectrumWalletAddresses walletAddresses;
@override @override
@observable @observable
ObservableMap<CryptoCurrency, ElectrumBalance> balance; late ObservableMap<CryptoCurrency, ElectrumBalance> balance;
@override @override
@observable @observable
@ -98,7 +102,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
.map((addr) => scriptHash(addr.address, networkType: networkType)) .map((addr) => scriptHash(addr.address, networkType: networkType))
.toList(); .toList();
String get xpub => hd.base58; String get xpub => hd.base58!;
@override @override
String get seed => mnemonic; String get seed => mnemonic;
@ -107,12 +111,12 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
@override @override
BitcoinWalletKeys get keys => BitcoinWalletKeys( BitcoinWalletKeys get keys => BitcoinWalletKeys(
wif: hd.wif, privateKey: hd.privKey, publicKey: hd.pubKey); wif: hd.wif!, privateKey: hd.privKey!, publicKey: hd.pubKey!);
String _password; String _password;
List<BitcoinUnspent> unspentCoins; List<BitcoinUnspent> unspentCoins;
List<int> _feeRates; List<int> _feeRates;
Map<String, BehaviorSubject<Object>> _scripthashesUpdateSubject; Map<String, BehaviorSubject<Object>?> _scripthashesUpdateSubject;
bool _isTransactionUpdating; bool _isTransactionUpdating;
Future<void> init() async { Future<void> init() async {
@ -137,7 +141,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
(timer) async => _feeRates = await electrumClient.feeRates()); (timer) async => _feeRates = await electrumClient.feeRates());
syncStatus = SyncedSyncStatus(); syncStatus = SyncedSyncStatus();
} catch (e) { } catch (e, stacktrace) {
print(stacktrace);
print(e.toString()); print(e.toString());
syncStatus = FailedSyncStatus(); syncStatus = FailedSyncStatus();
} }
@ -145,7 +150,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
@action @action
@override @override
Future<void> connectToNode({@required Node node}) async { Future<void> connectToNode({required Node node}) async {
try { try {
syncStatus = ConnectingSyncStatus(); syncStatus = ConnectingSyncStatus();
await electrumClient.connectToUri(node.uri); await electrumClient.connectToUri(node.uri);
@ -187,7 +192,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
} }
final allAmountFee = feeAmountForPriority( final allAmountFee = feeAmountForPriority(
transactionCredentials.priority, inputs.length, outputs.length); transactionCredentials.priority!, inputs.length, outputs.length);
final allAmount = allInputsAmount - allAmountFee; final allAmount = allInputsAmount - allAmountFee;
var credentialsAmount = 0; var credentialsAmount = 0;
@ -196,12 +201,12 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
if (hasMultiDestination) { if (hasMultiDestination) {
if (outputs.any((item) => item.sendAll if (outputs.any((item) => item.sendAll
|| item.formattedCryptoAmount <= 0)) { || item.formattedCryptoAmount! <= 0)) {
throw BitcoinTransactionWrongBalanceException(currency); throw BitcoinTransactionWrongBalanceException(currency);
} }
credentialsAmount = outputs.fold(0, (acc, value) => credentialsAmount = outputs.fold(0, (acc, value) =>
acc + value.formattedCryptoAmount); acc + value.formattedCryptoAmount!);
if (allAmount - credentialsAmount < minAmount) { if (allAmount - credentialsAmount < minAmount) {
throw BitcoinTransactionWrongBalanceException(currency); throw BitcoinTransactionWrongBalanceException(currency);
@ -210,7 +215,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
amount = credentialsAmount; amount = credentialsAmount;
if (transactionCredentials.feeRate != null) { if (transactionCredentials.feeRate != null) {
fee = calculateEstimatedFeeWithFeeRate(transactionCredentials.feeRate, amount, fee = calculateEstimatedFeeWithFeeRate(transactionCredentials.feeRate!, amount,
outputsCount: outputs.length + 1); outputsCount: outputs.length + 1);
} else { } else {
fee = calculateEstimatedFee(transactionCredentials.priority, amount, fee = calculateEstimatedFee(transactionCredentials.priority, amount,
@ -219,7 +224,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
} else { } else {
final output = outputs.first; final output = outputs.first;
credentialsAmount = !output.sendAll credentialsAmount = !output.sendAll
? output.formattedCryptoAmount ? output.formattedCryptoAmount!
: 0; : 0;
if (credentialsAmount > allAmount) { if (credentialsAmount > allAmount) {
@ -233,7 +238,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
if (output.sendAll || amount == allAmount) { if (output.sendAll || amount == allAmount) {
fee = allAmountFee; fee = allAmountFee;
} else if (transactionCredentials.feeRate != null) { } else if (transactionCredentials.feeRate != null) {
fee = calculateEstimatedFeeWithFeeRate(transactionCredentials.feeRate, amount); fee = calculateEstimatedFeeWithFeeRate(transactionCredentials.feeRate!, amount);
} else { } else {
fee = calculateEstimatedFee(transactionCredentials.priority, amount); fee = calculateEstimatedFee(transactionCredentials.priority, amount);
} }
@ -245,7 +250,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
final totalAmount = amount + fee; final totalAmount = amount + fee;
if (totalAmount > balance[currency].confirmed || totalAmount > allInputsAmount) { if (totalAmount > balance[currency]!.confirmed || totalAmount > allInputsAmount) {
throw BitcoinTransactionWrongBalanceException(currency); throw BitcoinTransactionWrongBalanceException(currency);
} }
@ -298,11 +303,11 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
? item.formattedCryptoAmount ? item.formattedCryptoAmount
: amount; : amount;
final outputAddress = item.isParsedAddress final outputAddress = item.isParsedAddress
? item.extractedAddress ? item.extractedAddress!
: item.address; : item.address;
txb.addOutput( txb.addOutput(
addressToOutputScript(outputAddress, networkType), addressToOutputScript(outputAddress, networkType),
outputAmount); outputAmount!);
}); });
final estimatedSize = final estimatedSize =
@ -310,9 +315,9 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
var feeAmount = 0; var feeAmount = 0;
if (transactionCredentials.feeRate != null) { if (transactionCredentials.feeRate != null) {
feeAmount = transactionCredentials.feeRate * estimatedSize; feeAmount = transactionCredentials.feeRate! * estimatedSize;
} else { } else {
feeAmount = feeRate(transactionCredentials.priority) * estimatedSize; feeAmount = feeRate(transactionCredentials.priority!) * estimatedSize;
} }
final changeValue = totalInputAmount - amount - feeAmount; final changeValue = totalInputAmount - amount - feeAmount;
@ -369,8 +374,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
feeRate * estimatedTransactionSize(inputsCount, outputsCount); feeRate * estimatedTransactionSize(inputsCount, outputsCount);
@override @override
int calculateEstimatedFee(TransactionPriority priority, int amount, int calculateEstimatedFee(TransactionPriority? priority, int? amount,
{int outputsCount}) { {int? outputsCount}) {
if (priority is BitcoinTransactionPriority) { if (priority is BitcoinTransactionPriority) {
return calculateEstimatedFeeWithFeeRate( return calculateEstimatedFeeWithFeeRate(
feeRate(priority), feeRate(priority),
@ -381,8 +386,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
return 0; return 0;
} }
int calculateEstimatedFeeWithFeeRate(int feeRate, int amount, int calculateEstimatedFeeWithFeeRate(int feeRate, int? amount,
{int outputsCount}) { {int? outputsCount}) {
int inputsCount = 0; int inputsCount = 0;
if (amount != null) { if (amount != null) {
@ -429,16 +434,16 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
await transactionHistory.changePassword(password); await transactionHistory.changePassword(password);
} }
bitcoin.ECPair keyPairFor({@required int index}) => bitcoin.ECPair keyPairFor({required int index}) =>
generateKeyPair(hd: hd, index: index, network: networkType); generateKeyPair(hd: hd, index: index, network: networkType);
@override @override
Future<void> rescan({int height}) async => throw UnimplementedError(); Future<void> rescan({required int height}) async => throw UnimplementedError();
@override @override
Future<void> close() async { Future<void> close() async {
try { try {
await electrumClient?.close(); await electrumClient.close();
} catch (_) {} } catch (_) {}
} }
@ -450,7 +455,13 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
.addresses.map((address) => electrumClient .addresses.map((address) => electrumClient
.getListUnspentWithAddress(address.address, networkType) .getListUnspentWithAddress(address.address, networkType)
.then((unspent) => unspent .then((unspent) => unspent
.map((unspent) => BitcoinUnspent.fromJSON(address, unspent))))); .map((unspent) {
try {
return BitcoinUnspent.fromJSON(address, unspent);
} catch(_) {
return null;
}
}).whereNotNull())));
unspentCoins = unspent.expand((e) => e).toList(); unspentCoins = unspent.expand((e) => e).toList();
if (unspentCoinsInfo.isEmpty) { if (unspentCoinsInfo.isEmpty) {
@ -484,7 +495,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
hash: coin.hash, hash: coin.hash,
isFrozen: coin.isFrozen, isFrozen: coin.isFrozen,
isSending: coin.isSending, isSending: coin.isSending,
note: coin.note noteRaw: coin.note
); );
await unspentCoinsInfo.add(newInfo); await unspentCoinsInfo.add(newInfo);
@ -498,10 +509,9 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
if (currentWalletUnspentCoins.isNotEmpty) { if (currentWalletUnspentCoins.isNotEmpty) {
currentWalletUnspentCoins.forEach((element) { currentWalletUnspentCoins.forEach((element) {
final existUnspentCoins = unspentCoins final existUnspentCoins = unspentCoins.where((coin) => element.hash.contains(coin.hash));
?.where((coin) => element.hash.contains(coin?.hash));
if (existUnspentCoins?.isEmpty ?? true) { if (existUnspentCoins.isEmpty) {
keys.add(element.key); keys.add(element.key);
} }
}); });
@ -516,7 +526,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
} }
Future<ElectrumTransactionBundle> getTransactionExpanded( Future<ElectrumTransactionBundle> getTransactionExpanded(
{@required String hash, @required int height}) async { {required String hash, required int height}) async {
final verboseTransaction = await electrumClient.getTransactionRaw(hash: hash); final verboseTransaction = await electrumClient.getTransactionRaw(hash: hash);
final transactionHex = verboseTransaction['hex'] as String; final transactionHex = verboseTransaction['hex'] as String;
final original = bitcoin.Transaction.fromHex(transactionHex); final original = bitcoin.Transaction.fromHex(transactionHex);
@ -525,7 +535,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
final confirmations = verboseTransaction['confirmations'] as int ?? 0; final confirmations = verboseTransaction['confirmations'] as int ?? 0;
for (final vin in original.ins) { for (final vin in original.ins) {
final id = HEX.encode(vin.hash.reversed.toList()); final id = HEX.encode(vin.hash!.reversed.toList());
final txHex = await electrumClient.getTransactionHex(hash: id); final txHex = await electrumClient.getTransactionHex(hash: id);
final tx = bitcoin.Transaction.fromHex(txHex); final tx = bitcoin.Transaction.fromHex(txHex);
ins.add(tx); ins.add(tx);
@ -538,8 +548,9 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
confirmations: confirmations); confirmations: confirmations);
} }
Future<ElectrumTransactionInfo> fetchTransactionInfo( Future<ElectrumTransactionInfo?> fetchTransactionInfo(
{@required String hash, @required int height}) async { {required String hash, required int height}) async {
try {
final tx = await getTransactionExpanded(hash: hash, height: height); final tx = await getTransactionExpanded(hash: hash, height: height);
final addresses = walletAddresses.addresses.map((addr) => addr.address).toSet(); final addresses = walletAddresses.addresses.map((addr) => addr.address).toSet();
return ElectrumTransactionInfo.fromElectrumBundle( return ElectrumTransactionInfo.fromElectrumBundle(
@ -548,6 +559,9 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
networkType, networkType,
addresses: addresses, addresses: addresses,
height: height); height: height);
} catch(_) {
return null;
}
} }
@override @override
@ -567,19 +581,27 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
history.entries.forEach((historyItem) { history.entries.forEach((historyItem) {
if (historyItem.value.isNotEmpty) { if (historyItem.value.isNotEmpty) {
final address = addressHashes[historyItem.key]; final address = addressHashes[historyItem.key];
address.setAsUsed(); address?.setAsUsed();
normalizedHistories.addAll(historyItem.value); normalizedHistories.addAll(historyItem.value);
} }
}); });
}); });
final historiesWithDetails = await Future.wait( final historiesWithDetails = await Future.wait(
normalizedHistories normalizedHistories
.map((transaction) => fetchTransactionInfo( .map((transaction) {
hash: transaction['tx_hash'] as String, try {
height: transaction['height'] as int))); return fetchTransactionInfo(
hash: transaction['tx_hash'] as String,
height: transaction['height'] as int);
} catch(_) {
return Future.value(null);
}
}));
return historiesWithDetails.fold<Map<String, ElectrumTransactionInfo>>( return historiesWithDetails.fold<Map<String, ElectrumTransactionInfo>>(
<String, ElectrumTransactionInfo>{}, (acc, tx) { <String, ElectrumTransactionInfo>{}, (acc, tx) {
if (tx == null) {
return acc;
}
acc[tx.id] = acc[tx.id]?.updated(tx) ?? tx; acc[tx.id] = acc[tx.id]?.updated(tx) ?? tx;
return acc; return acc;
}); });
@ -597,7 +619,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
walletAddresses.updateReceiveAddresses(); walletAddresses.updateReceiveAddresses();
await transactionHistory.save(); await transactionHistory.save();
_isTransactionUpdating = false; _isTransactionUpdating = false;
} catch (e) { } catch (e, stacktrace) {
print(stacktrace);
print(e); print(e);
_isTransactionUpdating = false; _isTransactionUpdating = false;
} }
@ -637,8 +660,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
for (var i = 0; i < balances.length; i++) { for (var i = 0; i < balances.length; i++) {
final addressRecord = addresses[i]; final addressRecord = addresses[i];
final balance = balances[i]; final balance = balances[i];
final confirmed = balance['confirmed'] as int ?? 0; final confirmed = balance['confirmed'] as int? ?? 0;
final unconfirmed = balance['unconfirmed'] as int ?? 0; final unconfirmed = balance['unconfirmed'] as int? ?? 0;
totalConfirmed += confirmed; totalConfirmed += confirmed;
totalUnconfirmed += unconfirmed; totalUnconfirmed += unconfirmed;

View file

@ -4,7 +4,6 @@ import 'package:cw_bitcoin/electrum.dart';
import 'package:cw_bitcoin/script_hash.dart'; import 'package:cw_bitcoin/script_hash.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:flutter/foundation.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
part 'electrum_wallet_addresses.g.dart'; part 'electrum_wallet_addresses.g.dart';
@ -14,13 +13,13 @@ class ElectrumWalletAddresses = ElectrumWalletAddressesBase
abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
ElectrumWalletAddressesBase(WalletInfo walletInfo, ElectrumWalletAddressesBase(WalletInfo walletInfo,
{@required List<BitcoinAddressRecord> initialAddresses, {required this.mainHd,
required this.sideHd,
required this.electrumClient,
required this.networkType,
List<BitcoinAddressRecord>? initialAddresses,
int initialRegularAddressIndex = 0, int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0, int initialChangeAddressIndex = 0})
this.mainHd,
this.sideHd,
this.electrumClient,
this.networkType})
: addresses = ObservableList<BitcoinAddressRecord>.of( : addresses = ObservableList<BitcoinAddressRecord>.of(
(initialAddresses ?? []).toSet()), (initialAddresses ?? []).toSet()),
receiveAddresses = ObservableList<BitcoinAddressRecord>.of( receiveAddresses = ObservableList<BitcoinAddressRecord>.of(
@ -31,10 +30,9 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
(initialAddresses ?? []) (initialAddresses ?? [])
.where((addressRecord) => addressRecord.isHidden && !addressRecord.isUsed) .where((addressRecord) => addressRecord.isHidden && !addressRecord.isUsed)
.toSet()), .toSet()),
super(walletInfo) { currentReceiveAddressIndex = initialRegularAddressIndex,
currentReceiveAddressIndex = initialRegularAddressIndex; currentChangeAddressIndex = initialChangeAddressIndex,
currentChangeAddressIndex = initialChangeAddressIndex; super(walletInfo);
}
static const defaultReceiveAddressesCount = 22; static const defaultReceiveAddressesCount = 22;
static const defaultChangeAddressesCount = 17; static const defaultChangeAddressesCount = 17;
@ -124,17 +122,18 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
} }
Future<BitcoinAddressRecord> generateNewAddress( Future<BitcoinAddressRecord> generateNewAddress(
{bool isHidden = false, bitcoin.HDWallet hd}) async { {bitcoin.HDWallet? hd, bool isHidden = false}) async {
currentReceiveAddressIndex += 1; currentReceiveAddressIndex += 1;
// FIX-ME: Check logic for whichi HD should be used here ???
final address = BitcoinAddressRecord( final address = BitcoinAddressRecord(
getAddress(index: currentReceiveAddressIndex, hd: hd), getAddress(index: currentReceiveAddressIndex, hd: hd ?? sideHd),
index: currentReceiveAddressIndex, index: currentReceiveAddressIndex,
isHidden: isHidden); isHidden: isHidden);
addresses.add(address); addresses.add(address);
return address; return address;
} }
String getAddress({@required int index, @required bitcoin.HDWallet hd}) => ''; String getAddress({required int index, required bitcoin.HDWallet hd}) => '';
@override @override
Future<void> updateAddressesInBox() async { Future<void> updateAddressesInBox() async {
@ -239,7 +238,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
} }
Future<List<BitcoinAddressRecord>> _createNewAddresses(int count, Future<List<BitcoinAddressRecord>> _createNewAddresses(int count,
{int startIndex = 0, bitcoin.HDWallet hd, bool isHidden = false}) async { {required bitcoin.HDWallet hd, int startIndex = 0, bool isHidden = false}) async {
final list = <BitcoinAddressRecord>[]; final list = <BitcoinAddressRecord>[];
for (var i = startIndex; i < count + startIndex; i++) { for (var i = startIndex; i < count + startIndex; i++) {

View file

@ -6,7 +6,15 @@ import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
class ElectrumWallletSnapshot { class ElectrumWallletSnapshot {
ElectrumWallletSnapshot(this.name, this.type, this.password); ElectrumWallletSnapshot({
required this.name,
required this.type,
required this.password,
required this.mnemonic,
required this.addresses,
required this.balance,
required this.regularAddressIndex,
required this.changeAddressIndex});
final String name; final String name;
final String password; final String password;
@ -18,28 +26,34 @@ class ElectrumWallletSnapshot {
int regularAddressIndex; int regularAddressIndex;
int changeAddressIndex; int changeAddressIndex;
Future<void> load() async { static Future<ElectrumWallletSnapshot> load(String name, WalletType type, String password) async {
try { final path = await pathForWallet(name: name, type: type);
final path = await pathForWallet(name: name, type: type); final jsonSource = await read(path: path, password: password);
final jsonSource = await read(path: path, password: password); final data = json.decode(jsonSource) as Map;
final data = json.decode(jsonSource) as Map; final addressesTmp = data['addresses'] as List? ?? <Object>[];
final addressesTmp = data['addresses'] as List ?? <Object>[]; final mnemonic = data['mnemonic'] as String;
mnemonic = data['mnemonic'] as String; final addresses = addressesTmp
addresses = addressesTmp .whereType<String>()
.whereType<String>() .map((addr) => BitcoinAddressRecord.fromJSON(addr))
.map((addr) => BitcoinAddressRecord.fromJSON(addr)) .toList();
.toList(); final balance = ElectrumBalance.fromJSON(data['balance'] as String) ??
balance = ElectrumBalance.fromJSON(data['balance'] as String) ?? ElectrumBalance(confirmed: 0, unconfirmed: 0);
ElectrumBalance(confirmed: 0, unconfirmed: 0); var regularAddressIndex = 0;
regularAddressIndex = 0; var changeAddressIndex = 0;
changeAddressIndex = 0;
try { try {
regularAddressIndex = int.parse(data['account_index'] as String); regularAddressIndex = int.parse(data['account_index'] as String? ?? '0');
changeAddressIndex = int.parse(data['change_address_index'] as String); changeAddressIndex = int.parse(data['change_address_index'] as String? ?? '0');
} catch (_) {} } catch (_) {}
} catch (e) {
print(e); return ElectrumWallletSnapshot(
} name: name,
type: type,
password: password,
mnemonic: mnemonic,
addresses: addresses,
balance: balance,
regularAddressIndex: regularAddressIndex,
changeAddressIndex: changeAddressIndex);
} }
} }

View file

@ -1,12 +1,11 @@
import 'dart:io'; import 'dart:io';
import 'package:cw_core/key.dart'; import 'package:cw_core/key.dart';
import 'package:encrypt/encrypt.dart' as encrypt; import 'package:encrypt/encrypt.dart' as encrypt;
import 'package:flutter/foundation.dart';
Future<void> write( Future<void> write(
{@required String path, {required String path,
@required String password, required String password,
@required String data}) async { required String data}) async {
final keys = extractKeys(password); final keys = extractKeys(password);
final key = encrypt.Key.fromBase64(keys.first); final key = encrypt.Key.fromBase64(keys.first);
final iv = encrypt.IV.fromBase64(keys.last); final iv = encrypt.IV.fromBase64(keys.last);
@ -16,9 +15,9 @@ Future<void> write(
} }
Future<void> writeData( Future<void> writeData(
{@required String path, {required String path,
@required String password, required String password,
@required String data}) async { required String data}) async {
final keys = extractKeys(password); final keys = extractKeys(password);
final key = encrypt.Key.fromBase64(keys.first); final key = encrypt.Key.fromBase64(keys.first);
final iv = encrypt.IV.fromBase64(keys.last); final iv = encrypt.IV.fromBase64(keys.last);
@ -27,7 +26,7 @@ Future<void> writeData(
f.writeAsStringSync(encrypted); f.writeAsStringSync(encrypted);
} }
Future<String> read({@required String path, @required String password}) async { Future<String> read({required String path, required String password}) async {
final file = File(path); final file = File(path);
if (!file.existsSync()) { if (!file.existsSync()) {

View file

@ -1,5 +1,6 @@
import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart'; import 'package:cw_bitcoin/bitcoin_transaction_priority.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_bitcoin/litecoin_wallet_addresses.dart'; import 'package:cw_bitcoin/litecoin_wallet_addresses.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
@ -20,12 +21,13 @@ class LitecoinWallet = LitecoinWalletBase with _$LitecoinWallet;
abstract class LitecoinWalletBase extends ElectrumWallet with Store { abstract class LitecoinWalletBase extends ElectrumWallet with Store {
LitecoinWalletBase( LitecoinWalletBase(
{@required String mnemonic, {required String mnemonic,
@required String password, required String password,
@required WalletInfo walletInfo, required WalletInfo walletInfo,
@required Box<UnspentCoinsInfo> unspentCoinsInfo, required Box<UnspentCoinsInfo> unspentCoinsInfo,
List<BitcoinAddressRecord> initialAddresses, required Uint8List seedBytes,
ElectrumBalance initialBalance, List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0, int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0}) int initialChangeAddressIndex = 0})
: super( : super(
@ -35,7 +37,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
unspentCoinsInfo: unspentCoinsInfo, unspentCoinsInfo: unspentCoinsInfo,
networkType: litecoinNetwork, networkType: litecoinNetwork,
initialAddresses: initialAddresses, initialAddresses: initialAddresses,
initialBalance: initialBalance) { initialBalance: initialBalance,
seedBytes: seedBytes,
currency: CryptoCurrency.ltc) {
walletAddresses = LitecoinWalletAddresses( walletAddresses = LitecoinWalletAddresses(
walletInfo, walletInfo,
electrumClient: electrumClient, electrumClient: electrumClient,
@ -44,19 +48,40 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
initialChangeAddressIndex: initialChangeAddressIndex, initialChangeAddressIndex: initialChangeAddressIndex,
mainHd: hd, mainHd: hd,
sideHd: bitcoin.HDWallet sideHd: bitcoin.HDWallet
.fromSeed(mnemonicToSeedBytes(mnemonic), network: networkType) .fromSeed(seedBytes, network: networkType)
.derivePath("m/0'/1"), .derivePath("m/0'/1"),
networkType: networkType,); networkType: networkType,);
} }
static Future<LitecoinWallet> open({ static Future<LitecoinWallet> create({
@required String name, required String mnemonic,
@required WalletInfo walletInfo, required String password,
@required Box<UnspentCoinsInfo> unspentCoinsInfo, required WalletInfo walletInfo,
@required String password, required Box<UnspentCoinsInfo> unspentCoinsInfo,
List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0
}) async { }) async {
final snp = ElectrumWallletSnapshot(name, walletInfo.type, password); return LitecoinWallet(
await snp.load(); mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
seedBytes: await mnemonicToSeedBytes(mnemonic),
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex);
}
static Future<LitecoinWallet> open({
required String name,
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required String password,
}) async {
final snp = await ElectrumWallletSnapshot.load (name, walletInfo.type, password);
return LitecoinWallet( return LitecoinWallet(
mnemonic: snp.mnemonic, mnemonic: snp.mnemonic,
password: password, password: password,
@ -64,6 +89,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
unspentCoinsInfo: unspentCoinsInfo, unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp.addresses, initialAddresses: snp.addresses,
initialBalance: snp.balance, initialBalance: snp.balance,
seedBytes: await mnemonicToSeedBytes(snp.mnemonic),
initialRegularAddressIndex: snp.regularAddressIndex, initialRegularAddressIndex: snp.regularAddressIndex,
initialChangeAddressIndex: snp.changeAddressIndex); initialChangeAddressIndex: snp.changeAddressIndex);
} }

View file

@ -16,13 +16,13 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses
with Store { with Store {
LitecoinWalletAddressesBase( LitecoinWalletAddressesBase(
WalletInfo walletInfo, WalletInfo walletInfo,
{@required List<BitcoinAddressRecord> initialAddresses, {required bitcoin.HDWallet mainHd,
required bitcoin.HDWallet sideHd,
required bitcoin.NetworkType networkType,
required ElectrumClient electrumClient,
List<BitcoinAddressRecord>? initialAddresses,
int initialRegularAddressIndex = 0, int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0, int initialChangeAddressIndex = 0})
ElectrumClient electrumClient,
@required bitcoin.HDWallet mainHd,
@required bitcoin.HDWallet sideHd,
@required bitcoin.NetworkType networkType})
: super( : super(
walletInfo, walletInfo,
initialAddresses: initialAddresses, initialAddresses: initialAddresses,
@ -34,6 +34,6 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses
networkType: networkType); networkType: networkType);
@override @override
String getAddress({@required int index, @required bitcoin.HDWallet hd}) => String getAddress({required int index, required bitcoin.HDWallet hd}) =>
generateP2WPKHAddress(hd: hd, index: index, networkType: networkType); generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
} }

View file

@ -10,6 +10,7 @@ import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:collection/collection.dart';
class LitecoinWalletService extends WalletService< class LitecoinWalletService extends WalletService<
BitcoinNewWalletCredentials, BitcoinNewWalletCredentials,
@ -25,10 +26,10 @@ class LitecoinWalletService extends WalletService<
@override @override
Future<LitecoinWallet> create(BitcoinNewWalletCredentials credentials) async { Future<LitecoinWallet> create(BitcoinNewWalletCredentials credentials) async {
final wallet = LitecoinWallet( final wallet = await LitecoinWalletBase.create(
mnemonic: await generateMnemonic(), mnemonic: await generateMnemonic(),
password: credentials.password, password: credentials.password!,
walletInfo: credentials.walletInfo, walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource); unspentCoinsInfo: unspentCoinsInfoSource);
await wallet.save(); await wallet.save();
await wallet.init(); await wallet.init();
@ -42,9 +43,8 @@ class LitecoinWalletService extends WalletService<
@override @override
Future<LitecoinWallet> openWallet(String name, String password) async { Future<LitecoinWallet> openWallet(String name, String password) async {
final walletInfo = walletInfoSource.values.firstWhere( final walletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(name, getType()), (info) => info.id == WalletBase.idFor(name, getType()))!;
orElse: () => null);
final wallet = await LitecoinWalletBase.open( final wallet = await LitecoinWalletBase.open(
password: password, name: name, walletInfo: walletInfo, password: password, name: name, walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource); unspentCoinsInfo: unspentCoinsInfoSource);
@ -69,10 +69,10 @@ class LitecoinWalletService extends WalletService<
throw BitcoinMnemonicIsIncorrectException(); throw BitcoinMnemonicIsIncorrectException();
} }
final wallet = LitecoinWallet( final wallet = await LitecoinWalletBase.create(
password: credentials.password, password: credentials.password!,
mnemonic: credentials.mnemonic, mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo, walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource); unspentCoinsInfo: unspentCoinsInfoSource);
await wallet.save(); await wallet.save();
await wallet.init(); await wallet.init();

View file

@ -1,5 +1,4 @@
import 'package:cw_bitcoin/bitcoin_commit_transaction_exception.dart'; import 'package:cw_bitcoin/bitcoin_commit_transaction_exception.dart';
import 'package:flutter/foundation.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin; import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:cw_core/pending_transaction.dart'; import 'package:cw_core/pending_transaction.dart';
import 'package:cw_bitcoin/electrum.dart'; import 'package:cw_bitcoin/electrum.dart';
@ -10,9 +9,9 @@ import 'package:cw_core/wallet_type.dart';
class PendingBitcoinTransaction with PendingTransaction { class PendingBitcoinTransaction with PendingTransaction {
PendingBitcoinTransaction(this._tx, this.type, PendingBitcoinTransaction(this._tx, this.type,
{@required this.electrumClient, {required this.electrumClient,
@required this.amount, required this.amount,
@required this.fee}) required this.fee})
: _listeners = <void Function(ElectrumTransactionInfo transaction)>[]; : _listeners = <void Function(ElectrumTransactionInfo transaction)>[];
final WalletType type; final WalletType type;

View file

@ -1,8 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin; import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
String scriptHash(String address, {@required bitcoin.NetworkType networkType}) { String scriptHash(String address, {required bitcoin.NetworkType networkType}) {
final outputScript = final outputScript =
bitcoin.Address.addressToOutputScript(address, networkType); bitcoin.Address.addressToOutputScript(address, networkType);
final parts = sha256.convert(outputScript).toString().split(''); final parts = sha256.convert(outputScript).toString().split('');

View file

@ -5,51 +5,51 @@ import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
import 'package:hex/hex.dart'; import 'package:hex/hex.dart';
bitcoin.PaymentData generatePaymentData( bitcoin.PaymentData generatePaymentData(
{@required bitcoin.HDWallet hd, @required int index}) => {required bitcoin.HDWallet hd, required int index}) =>
PaymentData( PaymentData(
pubkey: Uint8List.fromList(HEX.decode(hd.derive(index).pubKey))); pubkey: Uint8List.fromList(HEX.decode(hd.derive(index).pubKey!)));
bitcoin.ECPair generateKeyPair( bitcoin.ECPair generateKeyPair(
{@required bitcoin.HDWallet hd, {required bitcoin.HDWallet hd,
@required int index, required int index,
bitcoin.NetworkType network}) => required bitcoin.NetworkType network}) =>
bitcoin.ECPair.fromWIF(hd.derive(index).wif, network: network); bitcoin.ECPair.fromWIF(hd.derive(index).wif!, network: network);
String generateP2WPKHAddress( String generateP2WPKHAddress(
{@required bitcoin.HDWallet hd, {required bitcoin.HDWallet hd,
@required int index, required int index,
bitcoin.NetworkType networkType}) => required bitcoin.NetworkType networkType}) =>
bitcoin bitcoin
.P2WPKH( .P2WPKH(
data: PaymentData( data: PaymentData(
pubkey: pubkey:
Uint8List.fromList(HEX.decode(hd.derive(index).pubKey))), Uint8List.fromList(HEX.decode(hd.derive(index).pubKey!))),
network: networkType) network: networkType)
.data .data
.address; .address!;
String generateP2WPKHAddressByPath( String generateP2WPKHAddressByPath(
{@required bitcoin.HDWallet hd, {required bitcoin.HDWallet hd,
@required String path, required String path,
bitcoin.NetworkType networkType}) => required bitcoin.NetworkType networkType}) =>
bitcoin bitcoin
.P2WPKH( .P2WPKH(
data: PaymentData( data: PaymentData(
pubkey: pubkey:
Uint8List.fromList(HEX.decode(hd.derivePath(path).pubKey))), Uint8List.fromList(HEX.decode(hd.derivePath(path).pubKey!))),
network: networkType) network: networkType)
.data .data
.address; .address!;
String generateP2PKHAddress( String generateP2PKHAddress(
{@required bitcoin.HDWallet hd, {required bitcoin.HDWallet hd,
@required int index, required int index,
bitcoin.NetworkType networkType}) => required bitcoin.NetworkType networkType}) =>
bitcoin bitcoin
.P2PKH( .P2PKH(
data: PaymentData( data: PaymentData(
pubkey: pubkey:
Uint8List.fromList(HEX.decode(hd.derive(index).pubKey))), Uint8List.fromList(HEX.decode(hd.derive(index).pubKey!))),
network: networkType) network: networkType)
.data .data
.address; .address!;

View file

@ -7,64 +7,64 @@ packages:
name: _fe_analyzer_shared name: _fe_analyzer_shared
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "14.0.0" version: "47.0.0"
analyzer: analyzer:
dependency: transitive dependency: transitive
description: description:
name: analyzer name: analyzer
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.41.2" version: "4.7.0"
args: args:
dependency: transitive dependency: transitive
description: description:
name: args name: args
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.6.0" version: "2.3.1"
asn1lib: asn1lib:
dependency: transitive dependency: transitive
description: description:
name: asn1lib name: asn1lib
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.6.5" version: "1.1.1"
async: async:
dependency: transitive dependency: transitive
description: description:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.5.0" version: "2.9.0"
bech32: bech32:
dependency: transitive dependency: transitive
description: description:
path: "." path: "."
ref: cake ref: "cake-0.2.1"
resolved-ref: "02fef082f20af13de00b4e64efb93a2c1e5e1cf2" resolved-ref: cafd1c270641e95017d57d69f55cca9831d4db56
url: "https://github.com/cake-tech/bech32.git" url: "https://github.com/cake-tech/bech32.git"
source: git source: git
version: "0.2.0" version: "0.2.1"
bip32: bip32:
dependency: transitive dependency: transitive
description: description:
name: bip32 name: bip32
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.7" version: "2.0.0"
bip39: bip39:
dependency: transitive dependency: transitive
description: description:
name: bip39 name: bip39
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.3" version: "1.0.6"
bitcoin_flutter: bitcoin_flutter:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: cake ref: cake-update-v2
resolved-ref: cbabfd87b6ce3cae6051a3e86ddb56e7a934e188 resolved-ref: "8f86453761c0c26e368392d0ff2c6f12f3b7397b"
url: "https://github.com/cake-tech/bitcoin_flutter.git" url: "https://github.com/cake-tech/bitcoin_flutter.git"
source: git source: git
version: "2.0.2" version: "2.0.2"
@ -81,133 +81,119 @@ packages:
name: bs58check name: bs58check
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.1" version: "1.0.2"
build: build:
dependency: transitive dependency: transitive
description: description:
name: build name: build
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.6.2" version: "2.3.1"
build_config: build_config:
dependency: transitive dependency: transitive
description: description:
name: build_config name: build_config
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.6" version: "1.1.0"
build_daemon: build_daemon:
dependency: transitive dependency: transitive
description: description:
name: build_daemon name: build_daemon
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.10" version: "3.1.0"
build_resolvers: build_resolvers:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_resolvers name: build_resolvers
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.5.3" version: "2.0.10"
build_runner: build_runner:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_runner name: build_runner
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.11.5" version: "2.2.1"
build_runner_core: build_runner_core:
dependency: transitive dependency: transitive
description: description:
name: build_runner_core name: build_runner_core
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "6.1.10" version: "7.2.4"
built_collection: built_collection:
dependency: transitive dependency: transitive
description: description:
name: built_collection name: built_collection
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.3.2" version: "5.1.1"
built_value: built_value:
dependency: transitive dependency: transitive
description: description:
name: built_value name: built_value
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "7.1.0" version: "8.4.1"
characters: characters:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.2.1"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
checked_yaml: checked_yaml:
dependency: transitive dependency: transitive
description: description:
name: checked_yaml name: checked_yaml
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.4" version: "2.0.1"
cli_util:
dependency: transitive
description:
name: cli_util
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.5"
clock: clock:
dependency: transitive dependency: transitive
description: description:
name: clock name: clock
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.1.1"
code_builder: code_builder:
dependency: transitive dependency: transitive
description: description:
name: code_builder name: code_builder
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.7.0" version: "4.3.0"
collection: collection:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.15.0" version: "1.16.0"
convert: convert:
dependency: transitive dependency: transitive
description: description:
name: convert name: convert
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.1" version: "3.0.2"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.5" version: "3.0.2"
cryptography: cryptography:
dependency: "direct main" dependency: "direct main"
description: description:
name: cryptography name: cryptography
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.4.1" version: "2.0.5"
cw_core: cw_core:
dependency: "direct main" dependency: "direct main"
description: description:
@ -221,35 +207,28 @@ packages:
name: dart_style name: dart_style
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.12" version: "2.2.4"
dartx:
dependency: transitive
description:
name: dartx
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.0"
encrypt: encrypt:
dependency: "direct main" dependency: "direct main"
description: description:
name: encrypt name: encrypt
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.0.3" version: "5.0.1"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
name: fake_async name: fake_async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.3.1"
ffi: ffi:
dependency: transitive dependency: transitive
description: description:
name: ffi name: ffi
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.2" version: "2.0.1"
file: file:
dependency: transitive dependency: transitive
description: description:
@ -263,7 +242,7 @@ packages:
name: fixnum name: fixnum
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.10.11" version: "1.0.1"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -275,12 +254,19 @@ packages:
name: flutter_mobx name: flutter_mobx
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0+2" version: "2.0.6+4"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
glob: glob:
dependency: transitive dependency: transitive
description: description:
@ -294,49 +280,49 @@ packages:
name: graphs name: graphs
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.0" version: "2.1.0"
hex: hex:
dependency: transitive dependency: transitive
description: description:
name: hex name: hex
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.2" version: "0.2.0"
hive: hive:
dependency: transitive dependency: transitive
description: description:
name: hive name: hive
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.4.4+1" version: "2.2.3"
hive_generator: hive_generator:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: hive_generator name: hive_generator
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.8.2" version: "1.1.3"
http: http:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.12.2" version: "0.13.5"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
name: http_multi_server name: http_multi_server
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.2.0" version: "3.2.1"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
name: http_parser name: http_parser
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.1.4" version: "4.0.1"
intl: intl:
dependency: "direct main" dependency: "direct main"
description: description:
@ -350,7 +336,7 @@ packages:
name: io name: io
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.5" version: "1.0.3"
js: js:
dependency: transitive dependency: transitive
description: description:
@ -364,7 +350,7 @@ packages:
name: json_annotation name: json_annotation
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.0.1" version: "4.7.0"
logging: logging:
dependency: transitive dependency: transitive
description: description:
@ -378,14 +364,21 @@ packages:
name: matcher name: matcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.12.10" version: "0.12.12"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.5"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.0" version: "1.8.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
@ -399,63 +392,77 @@ packages:
name: mobx name: mobx
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.1+4" version: "2.1.0"
mobx_codegen: mobx_codegen:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: mobx_codegen name: mobx_codegen
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.2" version: "2.0.7+3"
package_config: package_config:
dependency: transitive dependency: transitive
description: description:
name: package_config name: package_config
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.9.3" version: "2.1.0"
path: path:
dependency: transitive dependency: transitive
description: description:
name: path name: path
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.0" version: "1.8.2"
path_provider: path_provider:
dependency: "direct main" dependency: "direct main"
description: description:
name: path_provider name: path_provider
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.6.28" version: "2.0.11"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.20"
path_provider_ios:
dependency: transitive
description:
name: path_provider_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.11"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
name: path_provider_linux name: path_provider_linux
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.0.1+2" version: "2.1.7"
path_provider_macos: path_provider_macos:
dependency: transitive dependency: transitive
description: description:
name: path_provider_macos name: path_provider_macos
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.0.4+8" version: "2.0.6"
path_provider_platform_interface: path_provider_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: path_provider_platform_interface name: path_provider_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.4" version: "2.0.5"
path_provider_windows: path_provider_windows:
dependency: transitive dependency: transitive
description: description:
name: path_provider_windows name: path_provider_windows
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.0.5" version: "2.1.3"
pedantic: pedantic:
dependency: transitive dependency: transitive
description: description:
@ -476,14 +483,14 @@ packages:
name: plugin_platform_interface name: plugin_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.3" version: "2.1.3"
pointycastle: pointycastle:
dependency: transitive dependency: transitive
description: description:
name: pointycastle name: pointycastle
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.2" version: "3.6.2"
pool: pool:
dependency: transitive dependency: transitive
description: description:
@ -511,35 +518,28 @@ packages:
name: pubspec_parse name: pubspec_parse
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.8" version: "1.2.1"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.5"
rxdart: rxdart:
dependency: "direct main" dependency: "direct main"
description: description:
name: rxdart name: rxdart
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.26.0" version: "0.27.5"
shelf: shelf:
dependency: transitive dependency: transitive
description: description:
name: shelf name: shelf
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.7.9" version: "1.4.0"
shelf_web_socket: shelf_web_socket:
dependency: transitive dependency: transitive
description: description:
name: shelf_web_socket name: shelf_web_socket
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.4+1" version: "1.0.2"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -551,14 +551,21 @@ packages:
name: source_gen name: source_gen
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.9.10+3" version: "1.2.5"
source_helper:
dependency: transitive
description:
name: source_helper
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.3"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.0" version: "1.9.0"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -586,35 +593,28 @@ packages:
name: string_scanner name: string_scanner
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.1.1"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
name: term_glyph name: term_glyph
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.2.1"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.19" version: "0.4.12"
time:
dependency: transitive
description:
name: time
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.1"
timing: timing:
dependency: transitive dependency: transitive
description: description:
name: timing name: timing
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.1+3" version: "1.0.0"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -635,7 +635,7 @@ packages:
name: vector_math name: vector_math
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.0" version: "2.1.2"
watcher: watcher:
dependency: transitive dependency: transitive
description: description:
@ -649,21 +649,21 @@ packages:
name: web_socket_channel name: web_socket_channel
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "2.2.0"
win32: win32:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.5" version: "3.0.0"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
name: xdg_directories name: xdg_directories
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.2" version: "0.2.0+2"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:
@ -672,5 +672,5 @@ packages:
source: hosted source: hosted
version: "3.1.0" version: "3.1.0"
sdks: sdks:
dart: ">=2.12.0 <3.0.0" dart: ">=2.17.5 <3.0.0"
flutter: ">=1.20.0" flutter: ">=3.0.0"

View file

@ -6,35 +6,35 @@ author: Cake Wallet
homepage: https://cakewallet.com homepage: https://cakewallet.com
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.17.5 <3.0.0"
flutter: ">=1.17.0" flutter: ">=1.20.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
path_provider: ^1.4.0 path_provider: ^2.0.11
http: ^0.12.0+2 http: ^0.13.4
mobx: ^1.2.1+2 mobx: ^2.0.7+4
flutter_mobx: ^1.1.0+2 flutter_mobx: ^2.0.6+1
intl: ^0.17.0 intl: ^0.17.0
cw_core: cw_core:
path: ../cw_core path: ../cw_core
bitcoin_flutter: bitcoin_flutter:
git: git:
url: https://github.com/cake-tech/bitcoin_flutter.git url: https://github.com/cake-tech/bitcoin_flutter.git
ref: cake ref: cake-update-v2
rxdart: ^0.26.0 rxdart: ^0.27.5
unorm_dart: ^0.2.0 unorm_dart: ^0.2.0
cryptography: ^1.4.0 cryptography: ^2.0.5
encrypt: ^4.0.0 encrypt: ^5.0.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
build_runner: ^1.10.3 build_runner: ^2.1.11
build_resolvers: ^1.3.10 build_resolvers: ^2.0.9
mobx_codegen: ^1.1.0+1 mobx_codegen: ^2.0.7
hive_generator: ^0.8.1 hive_generator: ^1.1.3
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec # following page: https://dart.dev/tools/pub/pubspec

View file

@ -1,7 +1,7 @@
class Account { class Account {
Account({this.id, this.label}); Account({required this.id, required this.label});
Account.fromMap(Map map) Account.fromMap(Map<String, Object> map)
: this.id = map['id'] == null ? 0 : int.parse(map['id'] as String), : this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
this.label = (map['label'] ?? '') as String; this.label = (map['label'] ?? '') as String;

View file

@ -8,9 +8,9 @@ abstract class AccountList<T> {
List<T> getAll(); List<T> getAll();
Future addAccount({String label}); Future<void> addAccount({required String label});
Future setLabelAccount({int accountIndex, String label}); Future<void> setLabelAccount({required int accountIndex, required String label});
void refresh(); void refresh();
} }

View file

@ -47,7 +47,7 @@ class AmountConverter {
case CryptoCurrency.xusd: case CryptoCurrency.xusd:
return _moneroAmountToDouble(amount); return _moneroAmountToDouble(amount);
default: default:
return null; return 0.0;
} }
} }
@ -71,7 +71,7 @@ class AmountConverter {
case CryptoCurrency.xusd: case CryptoCurrency.xusd:
return _moneroParseAmount(amount); return _moneroParseAmount(amount);
default: default:
return null; return 0;
} }
} }
@ -97,11 +97,11 @@ class AmountConverter {
case CryptoCurrency.xusd: case CryptoCurrency.xusd:
return _moneroAmountToString(amount); return _moneroAmountToString(amount);
default: default:
return null; return '';
} }
} }
static double cryptoAmountToDouble({num amount, num divider}) => static double cryptoAmountToDouble({required num amount, required num divider}) =>
amount / divider; amount / divider;
static String _moneroAmountToString(int amount) => _moneroAmountFormat.format( static String _moneroAmountToString(int amount) => _moneroAmountFormat.format(

View file

@ -1 +1 @@
double cryptoAmountToDouble({num amount, num divider}) => amount / divider; double cryptoAmountToDouble({required num amount, required num divider}) => amount / divider;

View file

@ -5,12 +5,17 @@ part 'crypto_currency.g.dart';
@HiveType(typeId: 0) @HiveType(typeId: 0)
class CryptoCurrency extends EnumerableItem<int> with Serializable<int> { class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
const CryptoCurrency({final String title, this.tag, this.name, this.iconPath, final int raw}) const CryptoCurrency({
String title = '',
int raw = -1,
this.name,
this.iconPath,
this.tag,})
: super(title: title, raw: raw); : super(title: title, raw: raw);
final String tag; final String? tag;
final String name; final String? name;
final String iconPath; final String? iconPath;
static const all = [ static const all = [
CryptoCurrency.xmr, CryptoCurrency.xmr,
@ -23,16 +28,49 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
CryptoCurrency.eos, CryptoCurrency.eos,
CryptoCurrency.eth, CryptoCurrency.eth,
CryptoCurrency.ltc, CryptoCurrency.ltc,
CryptoCurrency.nano,
CryptoCurrency.trx, CryptoCurrency.trx,
CryptoCurrency.usdt, CryptoCurrency.usdt,
CryptoCurrency.usdterc20, CryptoCurrency.usdterc20,
CryptoCurrency.xlm, CryptoCurrency.xlm,
CryptoCurrency.xrp, CryptoCurrency.xrp,
CryptoCurrency.xhv, CryptoCurrency.xhv,
//CryptoCurrency.zaddr, CryptoCurrency.ape,
//CryptoCurrency.zec CryptoCurrency.avaxc,
CryptoCurrency.btt,
CryptoCurrency.bttbsc,
CryptoCurrency.doge,
CryptoCurrency.firo,
CryptoCurrency.usdttrc20,
CryptoCurrency.hbar,
CryptoCurrency.sc,
CryptoCurrency.sol,
CryptoCurrency.usdc,
CryptoCurrency.usdcsol,
CryptoCurrency.zaddr,
CryptoCurrency.zec,
CryptoCurrency.zen,
CryptoCurrency.xvg,
CryptoCurrency.usdcpoly,
CryptoCurrency.dcr,
CryptoCurrency.husd,
CryptoCurrency.kmd,
CryptoCurrency.mana,
CryptoCurrency.maticpoly,
CryptoCurrency.matic,
CryptoCurrency.mkr,
CryptoCurrency.near,
CryptoCurrency.oxt,
CryptoCurrency.paxg,
CryptoCurrency.pivx,
CryptoCurrency.rune,
CryptoCurrency.rvn,
CryptoCurrency.scrt,
CryptoCurrency.uni,
CryptoCurrency.stx,
]; ];
static const xmr = CryptoCurrency(title: 'XMR', iconPath: 'assets/images/monero_icon.png', name: 'Monero', raw: 0);
static const xmr = CryptoCurrency(title: 'XMR', iconPath: 'assets/images/monero_icon.png', name: 'Monero', raw: 0);
static const ada = CryptoCurrency(title: 'ADA', iconPath: 'assets/images/ada_icon.png', name: 'Cardano', raw: 1); static const ada = CryptoCurrency(title: 'ADA', iconPath: 'assets/images/ada_icon.png', name: 'Cardano', raw: 1);
static const bch = CryptoCurrency(title: 'BCH', iconPath: 'assets/images/bch_icon.png',name: 'Bitcoin Cash', raw: 2); static const bch = CryptoCurrency(title: 'BCH', iconPath: 'assets/images/bch_icon.png',name: 'Bitcoin Cash', raw: 2);
static const bnb = CryptoCurrency(title: 'BNB', iconPath: 'assets/images/bnb_icon.png', tag: 'BSC', name: 'Binance Coin', raw: 3); static const bnb = CryptoCurrency(title: 'BNB', iconPath: 'assets/images/bnb_icon.png', tag: 'BSC', name: 'Binance Coin', raw: 3);
@ -41,7 +79,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
static const dash = CryptoCurrency(title: 'DASH', iconPath: 'assets/images/dash_icon.png', name: 'Dash', raw: 6); static const dash = CryptoCurrency(title: 'DASH', iconPath: 'assets/images/dash_icon.png', name: 'Dash', raw: 6);
static const eos = CryptoCurrency(title: 'EOS', iconPath: 'assets/images/eos_icon.png', name: 'EOS', raw: 7); static const eos = CryptoCurrency(title: 'EOS', iconPath: 'assets/images/eos_icon.png', name: 'EOS', raw: 7);
static const eth = CryptoCurrency(title: 'ETH', iconPath: 'assets/images/eth_icon.png', name: 'Ethereum', raw: 8); static const eth = CryptoCurrency(title: 'ETH', iconPath: 'assets/images/eth_icon.png', name: 'Ethereum', raw: 8);
static const ltc = CryptoCurrency(title: 'LTC', iconPath: 'assets/images/litecoin-ltc_icon.png', name: 'Litecoin',raw: 9); static const ltc = CryptoCurrency(title: 'LTC', iconPath: 'assets/images/litecoin-ltc_icon.png', name: 'Litecoin', raw: 9);
static const nano = CryptoCurrency(title: 'NANO', raw: 10); static const nano = CryptoCurrency(title: 'NANO', raw: 10);
static const trx = CryptoCurrency(title: 'TRX', iconPath: 'assets/images/trx_icon.png', name: 'TRON', raw: 11); static const trx = CryptoCurrency(title: 'TRX', iconPath: 'assets/images/trx_icon.png', name: 'TRON', raw: 11);
static const usdt = CryptoCurrency(title: 'USDT', iconPath: 'assets/images/usdt_icon.png', tag: 'OMNI', name: 'USDT', raw: 12); static const usdt = CryptoCurrency(title: 'USDT', iconPath: 'assets/images/usdt_icon.png', tag: 'OMNI', name: 'USDT', raw: 12);
@ -64,10 +102,44 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
static const xnzd = CryptoCurrency(title: 'XNZD', tag: 'XHV', raw: 28); static const xnzd = CryptoCurrency(title: 'XNZD', tag: 'XHV', raw: 28);
static const xusd = CryptoCurrency(title: 'XUSD', tag: 'XHV', raw: 29); static const xusd = CryptoCurrency(title: 'XUSD', tag: 'XHV', raw: 29);
static const zaddr = CryptoCurrency(title: 'ZZEC', tag: 'ZEC', name: 'Shielded Zcash', iconPath: 'assets/images/zaddr_icon.png', raw: 30); static const ape = CryptoCurrency(title: 'APE', iconPath: 'assets/images/ape_icon.png', tag: 'ETH', raw: 30);
static const zec = CryptoCurrency(title: 'TZEC', tag: 'ZEC', name: 'Transparent Zcash', iconPath: 'assets/images/zec_icon.png', raw: 31); static const avaxc = CryptoCurrency(title: 'AVAX', iconPath: 'assets/images/avaxc_icon.png', tag: 'C-CHAIN', raw: 31);
static const btt = CryptoCurrency(title: 'BTT', iconPath: 'assets/images/btt_icon.png', raw: 32);
static const bttbsc = CryptoCurrency(title: 'BTT', iconPath: 'assets/images/bttbsc_icon.png', tag: 'BSC', raw: 33);
static const doge = CryptoCurrency(title: 'DOGE', iconPath: 'assets/images/doge_icon.png', raw: 34);
static const firo = CryptoCurrency(title: 'FIRO', iconPath: 'assets/images/firo_icon.png', raw: 35);
static const usdttrc20 = CryptoCurrency(title: 'USDT', iconPath: 'assets/images/usdttrc20_icon.png', tag: 'TRX', raw: 36);
static const hbar = CryptoCurrency(title: 'HBAR', iconPath: 'assets/images/hbar_icon.png', raw: 37);
static const sc = CryptoCurrency(title: 'SC', iconPath: 'assets/images/sc_icon.png', raw: 38);
static const sol = CryptoCurrency(title: 'SOL', iconPath: 'assets/images/sol_icon.png', raw: 39);
static const usdc = CryptoCurrency(title: 'USDC', iconPath: 'assets/images/usdc_icon.png', tag: 'ETH', raw: 40);
static const usdcsol = CryptoCurrency(title: 'USDC', iconPath: 'assets/images/usdcsol_icon.png', tag: 'SOL', raw: 41);
static const zaddr = CryptoCurrency(title: 'ZZEC', tag: 'ZEC', name: 'Shielded Zcash', iconPath: 'assets/images/zaddr_icon.png', raw: 42);
static const zec = CryptoCurrency(title: 'TZEC', tag: 'ZEC', name: 'Transparent Zcash', iconPath: 'assets/images/zec_icon.png', raw: 43);
static const zen = CryptoCurrency(title: 'ZEN', iconPath: 'assets/images/zen_icon.png', raw: 44);
static const xvg = CryptoCurrency(title: 'XVG', name: 'Verge', iconPath: 'assets/images/xvg_icon.png', raw: 45);
static CryptoCurrency deserialize({int raw}) { static const usdcpoly = CryptoCurrency(title: 'USDC', iconPath: 'assets/images/usdc_icon.png', tag: 'POLY', raw: 46);
static const dcr = CryptoCurrency(title: 'DCR', iconPath: 'assets/images/dcr_icon.png', raw: 47);
static const husd = CryptoCurrency(title: 'HUSD', iconPath: 'assets/images/husd_icon.png', tag: 'ETH', raw: 48);
static const kmd = CryptoCurrency(title: 'KMD', iconPath: 'assets/images/kmd_icon.png', raw: 49);
static const mana = CryptoCurrency(title: 'MANA', iconPath: 'assets/images/mana_icon.png', tag: 'ETH', raw: 50);
static const maticpoly = CryptoCurrency(title: 'MATIC', iconPath: 'assets/images/matic_icon.png', tag: 'POLY', raw: 51);
static const matic = CryptoCurrency(title: 'MATIC', iconPath: 'assets/images/matic_icon.png', tag: 'ETH', raw: 52);
static const mkr = CryptoCurrency(title: 'MKR', iconPath: 'assets/images/mkr_icon.png', tag: 'ETH', raw: 53);
static const near = CryptoCurrency(title: 'NEAR', iconPath: 'assets/images/near_icon.png', raw: 54);
static const oxt = CryptoCurrency(title: 'OXT', iconPath: 'assets/images/oxt_icon.png', tag: 'ETH', raw: 55);
static const paxg = CryptoCurrency(title: 'PAXG', iconPath: 'assets/images/paxg_icon.png', tag: 'ETH', raw: 56);
static const pivx = CryptoCurrency(title: 'PIVX', iconPath: 'assets/images/pivx_icon.png', raw: 57);
static const rune = CryptoCurrency(title: 'RUNE', iconPath: 'assets/images/rune_icon.png', raw: 58);
static const rvn = CryptoCurrency(title: 'RVN', iconPath: 'assets/images/rvn_icon.png', raw: 59);
static const scrt = CryptoCurrency(title: 'SCRT', iconPath: 'assets/images/scrt_icon.png', raw: 60);
static const uni = CryptoCurrency(title: 'UNI', iconPath: 'assets/images/uni_icon.png', tag: 'ETH', raw: 61);
static const stx = CryptoCurrency(title: 'STX', iconPath: 'assets/images/stx_icon.png', raw: 62);
static CryptoCurrency deserialize({required int raw}) {
switch (raw) { switch (raw) {
case 0: case 0:
return CryptoCurrency.xmr; return CryptoCurrency.xmr;
@ -130,11 +202,73 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
case 29: case 29:
return CryptoCurrency.xusd; return CryptoCurrency.xusd;
case 30: case 30:
return CryptoCurrency.zaddr; return CryptoCurrency.ape;
case 31: case 31:
return CryptoCurrency.avaxc;
case 32:
return CryptoCurrency.btt;
case 33:
return CryptoCurrency.bttbsc;
case 34:
return CryptoCurrency.doge;
case 35:
return CryptoCurrency.firo;
case 36:
return CryptoCurrency.usdttrc20;
case 37:
return CryptoCurrency.hbar;
case 38:
return CryptoCurrency.sc;
case 39:
return CryptoCurrency.sol;
case 40:
return CryptoCurrency.usdc;
case 41:
return CryptoCurrency.usdcsol;
case 42:
return CryptoCurrency.zaddr;
case 43:
return CryptoCurrency.zec; return CryptoCurrency.zec;
case 44:
return CryptoCurrency.zen;
case 45:
return CryptoCurrency.xvg;
case 46:
return CryptoCurrency.usdcpoly;
case 47:
return CryptoCurrency.dcr;
case 48:
return CryptoCurrency.husd;
case 49:
return CryptoCurrency.kmd;
case 50:
return CryptoCurrency.mana;
case 51:
return CryptoCurrency.maticpoly;
case 52:
return CryptoCurrency.matic;
case 53:
return CryptoCurrency.mkr;
case 54:
return CryptoCurrency.near;
case 55:
return CryptoCurrency.oxt;
case 56:
return CryptoCurrency.paxg;
case 57:
return CryptoCurrency.pivx;
case 58:
return CryptoCurrency.rune;
case 59:
return CryptoCurrency.rvn;
case 60:
return CryptoCurrency.scrt;
case 61:
return CryptoCurrency.uni;
case 62:
return CryptoCurrency.stx;
default: default:
return null; throw Exception('Unexpected token: $raw for CryptoCurrency deserialize');
} }
} }
@ -164,8 +298,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
return CryptoCurrency.nano; return CryptoCurrency.nano;
case 'trx': case 'trx':
return CryptoCurrency.trx; return CryptoCurrency.trx;
case 'usdt': case 'usdc':
return CryptoCurrency.usdt; return CryptoCurrency.usdc;
case 'usdterc20': case 'usdterc20':
return CryptoCurrency.usdterc20; return CryptoCurrency.usdterc20;
case 'xlm': case 'xlm':
@ -200,12 +334,74 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
return CryptoCurrency.xnzd; return CryptoCurrency.xnzd;
case 'xusd': case 'xusd':
return CryptoCurrency.xusd; return CryptoCurrency.xusd;
case 'ape':
return CryptoCurrency.ape;
case 'avax':
return CryptoCurrency.avaxc;
case 'btt':
return CryptoCurrency.btt;
case 'bttbsc':
return CryptoCurrency.bttbsc;
case 'doge':
return CryptoCurrency.doge;
case 'firo':
return CryptoCurrency.firo;
case 'usdttrc20':
return CryptoCurrency.usdttrc20;
case 'hbar':
return CryptoCurrency.hbar;
case 'sc':
return CryptoCurrency.sc;
case 'sol':
return CryptoCurrency.sol;
case 'usdt':
return CryptoCurrency.usdt;
case 'usdcsol':
return CryptoCurrency.usdcsol;
case 'zaddr': case 'zaddr':
return CryptoCurrency.zaddr; return CryptoCurrency.zaddr;
case 'zec': case 'zec':
return CryptoCurrency.zec; return CryptoCurrency.zec;
case 'zen':
return CryptoCurrency.zen;
case 'xvg':
return CryptoCurrency.xvg;
case 'usdcpoly':
return CryptoCurrency.usdcpoly;
case 'dcr':
return CryptoCurrency.dcr;
case 'husd':
return CryptoCurrency.husd;
case 'kmd':
return CryptoCurrency.kmd;
case 'mana':
return CryptoCurrency.mana;
case 'maticpoly':
return CryptoCurrency.maticpoly;
case 'matic':
return CryptoCurrency.matic;
case 'mkr':
return CryptoCurrency.mkr;
case 'near':
return CryptoCurrency.near;
case 'oxt':
return CryptoCurrency.oxt;
case 'paxg':
return CryptoCurrency.paxg;
case 'pivx':
return CryptoCurrency.pivx;
case 'rune':
return CryptoCurrency.rune;
case 'rvn':
return CryptoCurrency.rvn;
case 'scrt':
return CryptoCurrency.scrt;
case 'uni':
return CryptoCurrency.uni;
case 'stx':
return CryptoCurrency.stx;
default: default:
return null; throw Exception('Unexpected token: $raw for CryptoCurrency fromString');
} }
} }

View file

@ -12,6 +12,6 @@ CryptoCurrency currencyForWalletType(WalletType type) {
case WalletType.haven: case WalletType.haven:
return CryptoCurrency.xhv; return CryptoCurrency.xhv;
default: default:
return null; throw Exception('Unexpected wallet type: ${type.toString()} for CryptoCurrency currencyForWalletType');
} }
} }

View file

@ -1,7 +1,7 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
abstract class EnumerableItem<T> { abstract class EnumerableItem<T> {
const EnumerableItem({@required this.title, @required this.raw}); const EnumerableItem({required this.title, required this.raw});
final T raw; final T raw;
final String title; final String title;
@ -11,6 +11,6 @@ abstract class EnumerableItem<T> {
} }
mixin Serializable<T> on EnumerableItem<T> { mixin Serializable<T> on EnumerableItem<T> {
static Serializable deserialize<T>({T raw}) => null; static Serializable deserialize<T>({required T raw}) => throw Exception('Unimplemented');
T serialize() => raw; T serialize() => raw;
} }

View file

@ -85,7 +85,7 @@ final dates = {
"2020-11": 2220000 "2020-11": 2220000
}; };
int getMoneroHeigthByDate({DateTime date}) { int getMoneroHeigthByDate({required DateTime date}) {
final raw = '${date.year}' + '-' + '${date.month}'; final raw = '${date.year}' + '-' + '${date.month}';
final lastHeight = dates.values.last; final lastHeight = dates.values.last;
int startHeight; int startHeight;
@ -105,7 +105,7 @@ int getMoneroHeigthByDate({DateTime date}) {
final daysHeight = (differenceInDays * heightPerDay).round(); final daysHeight = (differenceInDays * heightPerDay).round();
height = endHeight + daysHeight; height = endHeight + daysHeight;
} else { } else {
startHeight = dates[raw]; startHeight = dates[raw]!;
final index = dates.values.toList().indexOf(startHeight); final index = dates.values.toList().indexOf(startHeight);
endHeight = dates.values.toList()[index + 1]; endHeight = dates.values.toList()[index + 1];
final heightPerDay = ((endHeight - startHeight) / 31).round(); final heightPerDay = ((endHeight - startHeight) / 31).round();

View file

@ -16,14 +16,14 @@ List<String> extractKeys(String key) {
return [_key, iv]; return [_key, iv];
} }
Future<String> encode({encrypt.Key key, encrypt.IV iv, String data}) async { Future<String> encode({required encrypt.Key key, required encrypt.IV iv, required String data}) async {
final encrypter = encrypt.Encrypter(encrypt.Salsa20(key)); final encrypter = encrypt.Encrypter(encrypt.Salsa20(key));
final encrypted = encrypter.encrypt(data, iv: iv); final encrypted = encrypter.encrypt(data, iv: iv);
return encrypted.base64; return encrypted.base64;
} }
Future<String> decode({String password, String data}) async { Future<String> decode({required String password, required String data}) async {
final keys = extractKeys(password); final keys = extractKeys(password);
final key = encrypt.Key.fromBase64(keys.first); final key = encrypt.Key.fromBase64(keys.first);
final iv = encrypt.IV.fromBase64(keys.last); final iv = encrypt.IV.fromBase64(keys.last);

View file

@ -7,12 +7,12 @@ final moneroAmountFormat = NumberFormat()
..maximumFractionDigits = moneroAmountLength ..maximumFractionDigits = moneroAmountLength
..minimumFractionDigits = 1; ..minimumFractionDigits = 1;
String moneroAmountToString({int amount}) => moneroAmountFormat String moneroAmountToString({required int amount}) => moneroAmountFormat
.format(cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider)) .format(cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider))
.replaceAll(',', ''); .replaceAll(',', '');
double moneroAmountToDouble({int amount}) => double moneroAmountToDouble({required int amount}) =>
cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider); cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider);
int moneroParseAmount({String amount}) => int moneroParseAmount({required String amount}) =>
(double.parse(amount) * moneroAmountDivider).toInt(); (double.parse(amount) * moneroAmountDivider).toInt();

View file

@ -1,17 +1,16 @@
import 'package:cw_core/balance.dart'; import 'package:cw_core/balance.dart';
import 'package:flutter/foundation.dart';
import 'package:cw_core/monero_amount_format.dart'; import 'package:cw_core/monero_amount_format.dart';
class MoneroBalance extends Balance { class MoneroBalance extends Balance {
MoneroBalance({@required this.fullBalance, @required this.unlockedBalance}) MoneroBalance({required this.fullBalance, required this.unlockedBalance})
: formattedFullBalance = moneroAmountToString(amount: fullBalance), : formattedFullBalance = moneroAmountToString(amount: fullBalance),
formattedUnlockedBalance = formattedUnlockedBalance =
moneroAmountToString(amount: unlockedBalance), moneroAmountToString(amount: unlockedBalance),
super(unlockedBalance, fullBalance); super(unlockedBalance, fullBalance);
MoneroBalance.fromString( MoneroBalance.fromString(
{@required this.formattedFullBalance, {required this.formattedFullBalance,
@required this.formattedUnlockedBalance}) required this.formattedUnlockedBalance})
: fullBalance = moneroParseAmount(amount: formattedFullBalance), : fullBalance = moneroParseAmount(amount: formattedFullBalance),
unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance), unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance),
super(moneroParseAmount(amount: formattedUnlockedBalance), super(moneroParseAmount(amount: formattedUnlockedBalance),

View file

@ -4,18 +4,18 @@ import 'package:cw_core/wallet_type.dart';
import 'package:cw_core/enumerable_item.dart'; import 'package:cw_core/enumerable_item.dart';
class MoneroTransactionPriority extends TransactionPriority { class MoneroTransactionPriority extends TransactionPriority {
const MoneroTransactionPriority({String title, int raw}) const MoneroTransactionPriority({required String title, required int raw})
: super(title: title, raw: raw); : super(title: title, raw: raw);
static const all = [ static const all = [
MoneroTransactionPriority.slow, MoneroTransactionPriority.slow,
MoneroTransactionPriority.regular, MoneroTransactionPriority.automatic,
MoneroTransactionPriority.medium, MoneroTransactionPriority.medium,
MoneroTransactionPriority.fast, MoneroTransactionPriority.fast,
MoneroTransactionPriority.fastest MoneroTransactionPriority.fastest
]; ];
static const slow = MoneroTransactionPriority(title: 'Slow', raw: 0); static const slow = MoneroTransactionPriority(title: 'Slow', raw: 0);
static const regular = MoneroTransactionPriority(title: 'Regular', raw: 1); static const automatic = MoneroTransactionPriority(title: 'Automatic', raw: 1);
static const medium = MoneroTransactionPriority(title: 'Medium', raw: 2); static const medium = MoneroTransactionPriority(title: 'Medium', raw: 2);
static const fast = MoneroTransactionPriority(title: 'Fast', raw: 3); static const fast = MoneroTransactionPriority(title: 'Fast', raw: 3);
static const fastest = MoneroTransactionPriority(title: 'Fastest', raw: 4); static const fastest = MoneroTransactionPriority(title: 'Fastest', raw: 4);
@ -29,7 +29,7 @@ class MoneroTransactionPriority extends TransactionPriority {
case WalletType.bitcoin: case WalletType.bitcoin:
return [ return [
MoneroTransactionPriority.slow, MoneroTransactionPriority.slow,
MoneroTransactionPriority.regular, MoneroTransactionPriority.automatic,
MoneroTransactionPriority.fast MoneroTransactionPriority.fast
]; ];
default: default:
@ -37,12 +37,12 @@ class MoneroTransactionPriority extends TransactionPriority {
} }
} }
static MoneroTransactionPriority deserialize({int raw}) { static MoneroTransactionPriority deserialize({required int raw}) {
switch (raw) { switch (raw) {
case 0: case 0:
return slow; return slow;
case 1: case 1:
return regular; return automatic;
case 2: case 2:
return medium; return medium;
case 3: case 3:
@ -50,7 +50,7 @@ class MoneroTransactionPriority extends TransactionPriority {
case 4: case 4:
return fastest; return fastest;
default: default:
return null; throw Exception('Unexpected token: $raw for MoneroTransactionPriority deserialize');
} }
} }
@ -59,8 +59,8 @@ class MoneroTransactionPriority extends TransactionPriority {
switch (this) { switch (this) {
case MoneroTransactionPriority.slow: case MoneroTransactionPriority.slow:
return 'Slow'; // S.current.transaction_priority_slow; return 'Slow'; // S.current.transaction_priority_slow;
case MoneroTransactionPriority.regular: case MoneroTransactionPriority.automatic:
return 'Regular'; // S.current.transaction_priority_regular; return 'Automatic'; // S.current.transaction_priority_regular;
case MoneroTransactionPriority.medium: case MoneroTransactionPriority.medium:
return 'Medium'; // S.current.transaction_priority_medium; return 'Medium'; // S.current.transaction_priority_medium;
case MoneroTransactionPriority.fast: case MoneroTransactionPriority.fast:

View file

@ -1,9 +1,9 @@
class MoneroWalletKeys { class MoneroWalletKeys {
const MoneroWalletKeys( const MoneroWalletKeys(
{this.privateSpendKey, {required this.privateSpendKey,
this.privateViewKey, required this.privateViewKey,
this.publicSpendKey, required this.publicSpendKey,
this.publicViewKey}); required this.publicViewKey});
final String publicViewKey; final String publicViewKey;
final String privateViewKey; final String privateViewKey;

View file

@ -1,7 +1,5 @@
import 'dart:io'; import 'dart:io';
import 'package:cw_core/keyable.dart'; import 'package:cw_core/keyable.dart';
import 'package:flutter/foundation.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
@ -11,44 +9,47 @@ import 'package:http/io_client.dart' as ioc;
part 'node.g.dart'; part 'node.g.dart';
Uri createUriFromElectrumAddress(String address) => Uri createUriFromElectrumAddress(String address) =>
Uri.tryParse('tcp://$address'); Uri.tryParse('tcp://$address')!;
@HiveType(typeId: Node.typeId) @HiveType(typeId: Node.typeId)
class Node extends HiveObject with Keyable { class Node extends HiveObject with Keyable {
Node( Node(
{@required String uri, {this.login,
@required WalletType type,
this.login,
this.password, this.password,
this.useSSL}) { this.useSSL,
uriRaw = uri; String? uri,
this.type = type; WalletType? type,}) {
if (uri != null) {
uriRaw = uri;
}
if (type != null) {
this.type = type;
}
} }
Node.fromMap(Map map) Node.fromMap(Map<String, Object?> map)
: uriRaw = map['uri'] as String ?? '', : uriRaw = map['uri'] as String? ?? '',
login = map['login'] as String, login = map['login'] as String?,
password = map['password'] as String, password = map['password'] as String?,
typeRaw = map['typeRaw'] as int, useSSL = map['useSSL'] as bool?;
useSSL = map['useSSL'] as bool;
static const typeId = 1; static const typeId = 1;
static const boxName = 'Nodes'; static const boxName = 'Nodes';
@HiveField(0) @HiveField(0, defaultValue: '')
String uriRaw; late String uriRaw;
@HiveField(1) @HiveField(1)
String login; String? login;
@HiveField(2) @HiveField(2)
String password; String? password;
@HiveField(3) @HiveField(3, defaultValue: 0)
int typeRaw; late int typeRaw;
@HiveField(4) @HiveField(4)
bool useSSL; bool? useSSL;
bool get isSSL => useSSL ?? false; bool get isSSL => useSSL ?? false;
@ -63,7 +64,7 @@ class Node extends HiveObject with Keyable {
case WalletType.haven: case WalletType.haven:
return Uri.http(uriRaw, ''); return Uri.http(uriRaw, '');
default: default:
return null; throw Exception('Unexpected type ${type.toString()} for Node uri');
} }
} }
@ -99,7 +100,6 @@ class Node extends HiveObject with Keyable {
} }
Future<bool> requestMoneroNode() async { Future<bool> requestMoneroNode() async {
final path = '/json_rpc'; final path = '/json_rpc';
final rpcUri = isSSL ? Uri.https(uri.authority, path) : Uri.http(uri.authority, path); final rpcUri = isSSL ? Uri.https(uri.authority, path) : Uri.http(uri.authority, path);
final realm = 'monero-rpc'; final realm = 'monero-rpc';

View file

@ -1,20 +1,20 @@
class OutputInfo { class OutputInfo {
const OutputInfo( const OutputInfo(
{this.fiatAmount, {required this.address,
this.cryptoAmount, required this.sendAll,
this.address, required this.isParsedAddress,
this.note, this.cryptoAmount,
this.sendAll, this.formattedCryptoAmount,
this.extractedAddress, this.fiatAmount,
this.isParsedAddress, this.note,
this.formattedCryptoAmount}); this.extractedAddress,});
final String fiatAmount; final String? fiatAmount;
final String cryptoAmount; final String? cryptoAmount;
final String address; final String address;
final String note; final String? note;
final String extractedAddress; final String? extractedAddress;
final bool sendAll; final bool sendAll;
final bool isParsedAddress; final bool isParsedAddress;
final int formattedCryptoAmount; final int? formattedCryptoAmount;
} }

View file

@ -3,7 +3,7 @@ import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
Future<String> pathForWalletDir({@required String name, @required WalletType type}) async { Future<String> pathForWalletDir({required String name, required WalletType type}) async {
final root = await getApplicationDocumentsDirectory(); final root = await getApplicationDocumentsDirectory();
final prefix = walletTypeToString(type).toLowerCase(); final prefix = walletTypeToString(type).toLowerCase();
final walletsDir = Directory('${root.path}/wallets'); final walletsDir = Directory('${root.path}/wallets');
@ -16,11 +16,11 @@ Future<String> pathForWalletDir({@required String name, @required WalletType ty
return walletDire.path; return walletDire.path;
} }
Future<String> pathForWallet({@required String name, @required WalletType type}) async => Future<String> pathForWallet({required String name, required WalletType type}) async =>
await pathForWalletDir(name: name, type: type) await pathForWalletDir(name: name, type: type)
.then((path) => path + '/$name'); .then((path) => path + '/$name');
Future<String> outdatedAndroidPathForWalletDir({String name}) async { Future<String> outdatedAndroidPathForWalletDir({required String name}) async {
final directory = await getApplicationDocumentsDirectory(); final directory = await getApplicationDocumentsDirectory();
final pathDir = directory.path + '/$name'; final pathDir = directory.path + '/$name';

View file

@ -6,7 +6,7 @@ const utils = const MethodChannel('com.cake_wallet/native_utils');
Future<Uint8List> secRandom(int count) async { Future<Uint8List> secRandom(int count) async {
try { try {
return await utils.invokeMethod<Uint8List>('sec_random', {'count': count}); return await utils.invokeMethod<Uint8List>('sec_random', {'count': count}) ?? Uint8List.fromList([]);
} on PlatformException catch (_) { } on PlatformException catch (_) {
return Uint8List.fromList([]); return Uint8List.fromList([]);
} }

View file

@ -1,7 +1,7 @@
class Subaddress { class Subaddress {
Subaddress({this.id, this.address, this.label}); Subaddress({required this.id, required this.address, required this.label});
Subaddress.fromMap(Map map) Subaddress.fromMap(Map<String, Object?> map)
: this.id = map['id'] == null ? 0 : int.parse(map['id'] as String), : this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
this.address = (map['address'] ?? '') as String, this.address = (map['address'] ?? '') as String,
this.label = (map['label'] ?? '') as String; this.label = (map['label'] ?? '') as String;

View file

@ -2,16 +2,22 @@ enum TransactionDirection { incoming, outgoing }
TransactionDirection parseTransactionDirectionFromInt(int raw) { TransactionDirection parseTransactionDirectionFromInt(int raw) {
switch (raw) { switch (raw) {
case 0: return TransactionDirection.incoming; case 0:
case 1: return TransactionDirection.outgoing; return TransactionDirection.incoming;
default: return null; case 1:
return TransactionDirection.outgoing;
default:
throw Exception('Unexpected token: raw for TransactionDirection parseTransactionDirectionFromInt');
} }
} }
TransactionDirection parseTransactionDirectionFromNumber(String raw) { TransactionDirection parseTransactionDirectionFromNumber(String raw) {
switch (raw) { switch (raw) {
case "0": return TransactionDirection.incoming; case "0":
case "1": return TransactionDirection.outgoing; return TransactionDirection.incoming;
default: return null; case "1":
return TransactionDirection.outgoing;
default:
throw Exception('Unexpected token: raw for TransactionDirection parseTransactionDirectionFromNumber');
} }
} }

View file

@ -1,10 +1,9 @@
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/transaction_info.dart';
abstract class TransactionHistoryBase<TransactionType extends TransactionInfo> { abstract class TransactionHistoryBase<TransactionType extends TransactionInfo> {
TransactionHistoryBase(); TransactionHistoryBase()
// : _isUpdating = false; : transactions = ObservableMap<String, TransactionType>();
@observable @observable
ObservableMap<String, TransactionType> transactions; ObservableMap<String, TransactionType> transactions;

View file

@ -2,21 +2,21 @@ import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/keyable.dart'; import 'package:cw_core/keyable.dart';
abstract class TransactionInfo extends Object with Keyable { abstract class TransactionInfo extends Object with Keyable {
String id; late String id;
int amount; late int amount;
int fee; int? fee;
TransactionDirection direction; late TransactionDirection direction;
bool isPending; late bool isPending;
DateTime date; late DateTime date;
int height; late int height;
int confirmations; late int confirmations;
String amountFormatted(); String amountFormatted();
String fiatAmount(); String fiatAmount();
String feeFormatted(); String? feeFormatted();
void changeFiatAmount(String amount); void changeFiatAmount(String amount);
@override @override
dynamic get keyIndex => id; dynamic get keyIndex => id;
Map<String, dynamic> additionalInfo; late Map<String, dynamic> additionalInfo;
} }

View file

@ -2,5 +2,5 @@ import 'package:cw_core/enumerable_item.dart';
abstract class TransactionPriority extends EnumerableItem<int> abstract class TransactionPriority extends EnumerableItem<int>
with Serializable<int> { with Serializable<int> {
const TransactionPriority({String title, int raw}) : super(title: title, raw: raw); const TransactionPriority({required String title, required int raw}) : super(title: title, raw: raw);
} }

View file

@ -5,28 +5,32 @@ part 'unspent_coins_info.g.dart';
@HiveType(typeId: UnspentCoinsInfo.typeId) @HiveType(typeId: UnspentCoinsInfo.typeId)
class UnspentCoinsInfo extends HiveObject { class UnspentCoinsInfo extends HiveObject {
UnspentCoinsInfo({ UnspentCoinsInfo({
this.walletId, required this.walletId,
this.hash, required this.hash,
this.isFrozen, required this.isFrozen,
this.isSending, required this.isSending,
this.note}); required this.noteRaw});
static const typeId = 9; static const typeId = 9;
static const boxName = 'Unspent'; static const boxName = 'Unspent';
static const boxKey = 'unspentBoxKey'; static const boxKey = 'unspentBoxKey';
@HiveField(0) @HiveField(0, defaultValue: '')
String walletId; String walletId;
@HiveField(1) @HiveField(1, defaultValue: '')
String hash; String hash;
@HiveField(2) @HiveField(2, defaultValue: false)
bool isFrozen; bool isFrozen;
@HiveField(3) @HiveField(3, defaultValue: false)
bool isSending; bool isSending;
@HiveField(4) @HiveField(4)
String note; String? noteRaw;
String get note => noteRaw ?? '';
set note(String value) => noteRaw = value;
} }

View file

@ -1,9 +1,8 @@
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
abstract class WalletAddresses { abstract class WalletAddresses {
WalletAddresses(this.walletInfo) { WalletAddresses(this.walletInfo)
addressesMap = {}; : addressesMap = {};
}
final WalletInfo walletInfo; final WalletInfo walletInfo;
@ -19,10 +18,6 @@ abstract class WalletAddresses {
Future<void> saveAddressesInBox() async { Future<void> saveAddressesInBox() async {
try { try {
if (walletInfo == null) {
return;
}
walletInfo.address = address; walletInfo.address = address;
walletInfo.addresses = addressesMap; walletInfo.addresses = addressesMap;

View file

@ -5,9 +5,9 @@ import 'package:cw_core/wallet_info.dart';
abstract class WalletAddressesWithAccount<T> extends WalletAddresses { abstract class WalletAddressesWithAccount<T> extends WalletAddresses {
WalletAddressesWithAccount(WalletInfo walletInfo) : super(walletInfo); WalletAddressesWithAccount(WalletInfo walletInfo) : super(walletInfo);
T get account; // T get account;
set account(T account); // set account(T account);
AccountList<T> get accountList; AccountList<T> get accountList;
} }

View file

@ -1,12 +1,12 @@
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cw_core/balance.dart'; import 'package:cw_core/balance.dart';
import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_addresses.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/pending_transaction.dart'; import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/currency_for_wallet_type.dart'; import 'package:cw_core/currency_for_wallet_type.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
@ -48,15 +48,15 @@ abstract class WalletBase<
WalletAddresses get walletAddresses; WalletAddresses get walletAddresses;
HistoryType transactionHistory; late HistoryType transactionHistory;
Future<void> connectToNode({@required Node node}); Future<void> connectToNode({required Node node});
Future<void> startSync(); Future<void> startSync();
Future<PendingTransaction> createTransaction(Object credentials); Future<PendingTransaction> createTransaction(Object credentials);
int calculateEstimatedFee(TransactionPriority priority, int amount); int calculateEstimatedFee(TransactionPriority priority, int? amount);
// void fetchTransactionsAsync( // void fetchTransactionsAsync(
// void Function(TransactionType transaction) onTransactionLoaded, // void Function(TransactionType transaction) onTransactionLoaded,
@ -66,7 +66,7 @@ abstract class WalletBase<
Future<void> save(); Future<void> save();
Future<void> rescan({int height}); Future<void> rescan({required int height});
void close(); void close();

View file

@ -1,10 +1,14 @@
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
abstract class WalletCredentials { abstract class WalletCredentials {
WalletCredentials({this.name, this.password, this.height, this.walletInfo}); WalletCredentials({
required this.name,
this.height,
this.walletInfo,
this.password});
final String name; final String name;
final int height; final int? height;
String password; String? password;
WalletInfo walletInfo; WalletInfo? walletInfo;
} }

View file

@ -9,66 +9,70 @@ part 'wallet_info.g.dart';
class WalletInfo extends HiveObject { class WalletInfo extends HiveObject {
WalletInfo(this.id, this.name, this.type, this.isRecovery, this.restoreHeight, WalletInfo(this.id, this.name, this.type, this.isRecovery, this.restoreHeight,
this.timestamp, this.dirPath, this.path, this.address, this.yatEid, this.timestamp, this.dirPath, this.path, this.address, this.yatEid,
this.yatLastUsedAddressRaw) this.yatLastUsedAddressRaw, this.showIntroCakePayCard)
: _yatLastUsedAddressController = StreamController<String>.broadcast(); : _yatLastUsedAddressController = StreamController<String>.broadcast();
factory WalletInfo.external( factory WalletInfo.external(
{@required String id, {required String id,
@required String name, required String name,
@required WalletType type, required WalletType type,
@required bool isRecovery, required bool isRecovery,
@required int restoreHeight, required int restoreHeight,
@required DateTime date, required DateTime date,
@required String dirPath, required String dirPath,
@required String path, required String path,
@required String address, required String address,
bool? showIntroCakePayCard,
String yatEid ='', String yatEid ='',
String yatLastUsedAddressRaw = ''}) { String yatLastUsedAddressRaw = ''}) {
return WalletInfo(id, name, type, isRecovery, restoreHeight, return WalletInfo(id, name, type, isRecovery, restoreHeight,
date.millisecondsSinceEpoch ?? 0, dirPath, path, address, date.millisecondsSinceEpoch, dirPath, path, address,
yatEid, yatLastUsedAddressRaw); yatEid, yatLastUsedAddressRaw, showIntroCakePayCard);
} }
static const typeId = 4; static const typeId = 4;
static const boxName = 'WalletInfo'; static const boxName = 'WalletInfo';
@HiveField(0) @HiveField(0, defaultValue: '')
String id; String id;
@HiveField(1) @HiveField(1, defaultValue: '')
String name; String name;
@HiveField(2) @HiveField(2)
WalletType type; WalletType type;
@HiveField(3) @HiveField(3, defaultValue: false)
bool isRecovery; bool isRecovery;
@HiveField(4) @HiveField(4, defaultValue: 0)
int restoreHeight; int restoreHeight;
@HiveField(5) @HiveField(5, defaultValue: 0)
int timestamp; int timestamp;
@HiveField(6) @HiveField(6, defaultValue: '')
String dirPath; String dirPath;
@HiveField(7) @HiveField(7, defaultValue: '')
String path; String path;
@HiveField(8) @HiveField(8, defaultValue: '')
String address; String address;
@HiveField(10) @HiveField(10)
Map<String, String> addresses; Map<String, String>? addresses;
@HiveField(11) @HiveField(11)
String yatEid; String? yatEid;
@HiveField(12) @HiveField(12)
String yatLastUsedAddressRaw; String? yatLastUsedAddressRaw;
String get yatLastUsedAddress => yatLastUsedAddressRaw; @HiveField(13)
bool? showIntroCakePayCard;
String get yatLastUsedAddress => yatLastUsedAddressRaw ?? '';
set yatLastUsedAddress(String address) { set yatLastUsedAddress(String address) {
yatLastUsedAddressRaw = address; yatLastUsedAddressRaw = address;
@ -77,6 +81,13 @@ class WalletInfo extends HiveObject {
String get yatEmojiId => yatEid ?? ''; String get yatEmojiId => yatEid ?? '';
bool get isShowIntroCakePayCard {
if(showIntroCakePayCard == null) {
return type != WalletType.haven;
}
return showIntroCakePayCard!;
}
DateTime get date => DateTime.fromMillisecondsSinceEpoch(timestamp); DateTime get date => DateTime.fromMillisecondsSinceEpoch(timestamp);
Stream<String> get yatLastUsedAddressStream => _yatLastUsedAddressController.stream; Stream<String> get yatLastUsedAddressStream => _yatLastUsedAddressController.stream;

View file

@ -55,7 +55,7 @@ WalletType deserializeFromInt(int raw) {
case 3: case 3:
return WalletType.haven; return WalletType.haven;
default: default:
return null; throw Exception('Unexpected token: $raw for WalletType deserializeFromInt');
} }
} }
@ -100,6 +100,6 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type) {
case WalletType.haven: case WalletType.haven:
return CryptoCurrency.xhv; return CryptoCurrency.xhv;
default: default:
return null; throw Exception('Unexpected wallet type: ${type.toString()} for CryptoCurrency walletTypeToCryptoCurrency');
} }
} }

View file

@ -7,35 +7,35 @@ packages:
name: _fe_analyzer_shared name: _fe_analyzer_shared
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "14.0.0" version: "47.0.0"
analyzer: analyzer:
dependency: transitive dependency: transitive
description: description:
name: analyzer name: analyzer
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.41.2" version: "4.7.0"
args: args:
dependency: transitive dependency: transitive
description: description:
name: args name: args
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.6.0" version: "2.3.1"
asn1lib: asn1lib:
dependency: transitive dependency: transitive
description: description:
name: asn1lib name: asn1lib
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.8.1" version: "1.1.1"
async: async:
dependency: transitive dependency: transitive
description: description:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.5.0" version: "2.9.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -49,42 +49,42 @@ packages:
name: build name: build
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.6.2" version: "2.3.1"
build_config: build_config:
dependency: transitive dependency: transitive
description: description:
name: build_config name: build_config
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.6" version: "1.1.0"
build_daemon: build_daemon:
dependency: transitive dependency: transitive
description: description:
name: build_daemon name: build_daemon
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.10" version: "3.1.0"
build_resolvers: build_resolvers:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_resolvers name: build_resolvers
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.5.3" version: "2.0.10"
build_runner: build_runner:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_runner name: build_runner
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.11.5" version: "2.2.1"
build_runner_core: build_runner_core:
dependency: transitive dependency: transitive
description: description:
name: build_runner_core name: build_runner_core
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "6.1.10" version: "7.2.4"
built_collection: built_collection:
dependency: transitive dependency: transitive
description: description:
@ -105,98 +105,77 @@ packages:
name: characters name: characters
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.2.1"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
checked_yaml: checked_yaml:
dependency: transitive dependency: transitive
description: description:
name: checked_yaml name: checked_yaml
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.4" version: "2.0.1"
cli_util:
dependency: transitive
description:
name: cli_util
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.5"
clock: clock:
dependency: transitive dependency: transitive
description: description:
name: clock name: clock
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.1.1"
code_builder: code_builder:
dependency: transitive dependency: transitive
description: description:
name: code_builder name: code_builder
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.7.0" version: "4.3.0"
collection: collection:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.15.0" version: "1.16.0"
convert: convert:
dependency: transitive dependency: transitive
description: description:
name: convert name: convert
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.1" version: "3.0.2"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.5" version: "3.0.2"
dart_style: dart_style:
dependency: transitive dependency: transitive
description: description:
name: dart_style name: dart_style
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.12" version: "2.2.4"
dartx:
dependency: transitive
description:
name: dartx
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.0"
encrypt: encrypt:
dependency: "direct main" dependency: "direct main"
description: description:
name: encrypt name: encrypt
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.1.0" version: "5.0.1"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
name: fake_async name: fake_async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.3.1"
ffi: ffi:
dependency: transitive dependency: transitive
description: description:
name: ffi name: ffi
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.2" version: "2.0.1"
file: file:
dependency: transitive dependency: transitive
description: description:
@ -222,12 +201,19 @@ packages:
name: flutter_mobx name: flutter_mobx
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0+2" version: "2.0.6+4"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
glob: glob:
dependency: transitive dependency: transitive
description: description:
@ -241,42 +227,42 @@ packages:
name: graphs name: graphs
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.0" version: "2.1.0"
hive: hive:
dependency: transitive dependency: transitive
description: description:
name: hive name: hive
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.4.4+1" version: "2.2.3"
hive_generator: hive_generator:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: hive_generator name: hive_generator
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.8.2" version: "1.1.3"
http: http:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.12.2" version: "0.13.5"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
name: http_multi_server name: http_multi_server
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.2.0" version: "3.2.1"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
name: http_parser name: http_parser
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.1.4" version: "4.0.1"
intl: intl:
dependency: "direct main" dependency: "direct main"
description: description:
@ -290,7 +276,7 @@ packages:
name: io name: io
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.5" version: "1.0.3"
js: js:
dependency: transitive dependency: transitive
description: description:
@ -304,7 +290,7 @@ packages:
name: json_annotation name: json_annotation
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.0.1" version: "4.6.0"
logging: logging:
dependency: transitive dependency: transitive
description: description:
@ -318,14 +304,21 @@ packages:
name: matcher name: matcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.12.10" version: "0.12.12"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.5"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.0" version: "1.8.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
@ -339,63 +332,77 @@ packages:
name: mobx name: mobx
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.1+4" version: "2.1.0"
mobx_codegen: mobx_codegen:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: mobx_codegen name: mobx_codegen
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.2" version: "2.0.7+3"
package_config: package_config:
dependency: transitive dependency: transitive
description: description:
name: package_config name: package_config
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.9.3" version: "2.1.0"
path: path:
dependency: transitive dependency: transitive
description: description:
name: path name: path
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.0" version: "1.8.2"
path_provider: path_provider:
dependency: "direct main" dependency: "direct main"
description: description:
name: path_provider name: path_provider
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.6.28" version: "2.0.11"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.20"
path_provider_ios:
dependency: transitive
description:
name: path_provider_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.11"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
name: path_provider_linux name: path_provider_linux
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.0.1+2" version: "2.1.7"
path_provider_macos: path_provider_macos:
dependency: transitive dependency: transitive
description: description:
name: path_provider_macos name: path_provider_macos
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.0.4+8" version: "2.0.6"
path_provider_platform_interface: path_provider_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: path_provider_platform_interface name: path_provider_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.4" version: "2.0.4"
path_provider_windows: path_provider_windows:
dependency: transitive dependency: transitive
description: description:
name: path_provider_windows name: path_provider_windows
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.0.5" version: "2.1.3"
pedantic: pedantic:
dependency: transitive dependency: transitive
description: description:
@ -416,14 +423,14 @@ packages:
name: plugin_platform_interface name: plugin_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.3" version: "2.1.3"
pointycastle: pointycastle:
dependency: transitive dependency: transitive
description: description:
name: pointycastle name: pointycastle
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.1" version: "3.6.2"
pool: pool:
dependency: transitive dependency: transitive
description: description:
@ -451,21 +458,21 @@ packages:
name: pubspec_parse name: pubspec_parse
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.8" version: "1.2.1"
shelf: shelf:
dependency: transitive dependency: transitive
description: description:
name: shelf name: shelf
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.7.9" version: "1.3.2"
shelf_web_socket: shelf_web_socket:
dependency: transitive dependency: transitive
description: description:
name: shelf_web_socket name: shelf_web_socket
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.4+1" version: "1.0.2"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -477,14 +484,21 @@ packages:
name: source_gen name: source_gen
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.9.10+3" version: "1.2.3"
source_helper:
dependency: transitive
description:
name: source_helper
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.3"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.0" version: "1.9.0"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -512,35 +526,28 @@ packages:
name: string_scanner name: string_scanner
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.1.1"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
name: term_glyph name: term_glyph
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.2.1"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.19" version: "0.4.12"
time:
dependency: transitive
description:
name: time
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.1"
timing: timing:
dependency: transitive dependency: transitive
description: description:
name: timing name: timing
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.1+3" version: "1.0.0"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -554,7 +561,7 @@ packages:
name: vector_math name: vector_math
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.0" version: "2.1.2"
watcher: watcher:
dependency: transitive dependency: transitive
description: description:
@ -568,21 +575,21 @@ packages:
name: web_socket_channel name: web_socket_channel
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "2.2.0"
win32: win32:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.5" version: "3.0.0"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
name: xdg_directories name: xdg_directories
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.2" version: "0.2.0+2"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:
@ -591,5 +598,5 @@ packages:
source: hosted source: hosted
version: "3.1.0" version: "3.1.0"
sdks: sdks:
dart: ">=2.12.0 <3.0.0" dart: ">=2.17.5 <3.0.0"
flutter: ">=1.20.0" flutter: ">=3.0.0"

View file

@ -6,26 +6,26 @@ author: Cake Wallet
homepage: https://cakewallet.com homepage: https://cakewallet.com
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.17.5 <3.0.0"
flutter: ">=1.17.0" flutter: ">=1.20.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
http: ^0.12.0+2 http: ^0.13.4
path_provider: ^1.3.0 path_provider: ^2.0.11
mobx: ^1.2.1+2 mobx: ^2.0.7+4
flutter_mobx: ^1.1.0+2 flutter_mobx: ^2.0.6+1
intl: ^0.17.0 intl: ^0.17.0
encrypt: ^4.0.0 encrypt: ^5.0.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
build_runner: ^1.10.3 build_runner: ^2.1.11
build_resolvers: ^1.3.10 build_resolvers: ^2.0.9
mobx_codegen: ^1.1.0+1 mobx_codegen: ^2.0.7
hive_generator: ^0.8.1 hive_generator: ^1.1.3
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec # following page: https://dart.dev/tools/pub/pubspec

View file

@ -50,16 +50,16 @@ List<AccountRow> getAllAccount() {
.toList(); .toList();
} }
void addAccountSync({String label}) { void addAccountSync({required String label}) {
final labelPointer = Utf8.toUtf8(label); final labelPointer = label.toNativeUtf8();
accountAddNewNative(labelPointer); accountAddNewNative(labelPointer);
free(labelPointer); calloc.free(labelPointer);
} }
void setLabelForAccountSync({int accountIndex, String label}) { void setLabelForAccountSync({required int accountIndex, required String label}) {
final labelPointer = Utf8.toUtf8(label); final labelPointer = label.toNativeUtf8();
accountSetLabelNative(accountIndex, labelPointer); accountSetLabelNative(accountIndex, labelPointer);
free(labelPointer); calloc.free(labelPointer);
} }
void _addAccount(String label) => addAccountSync(label: label); void _addAccount(String label) => addAccountSync(label: label);
@ -71,12 +71,12 @@ void _setLabelForAccount(Map<String, dynamic> args) {
setLabelForAccountSync(label: label, accountIndex: accountIndex); setLabelForAccountSync(label: label, accountIndex: accountIndex);
} }
Future<void> addAccount({String label}) async { Future<void> addAccount({required String label}) async {
await compute(_addAccount, label); await compute(_addAccount, label);
await store(); await store();
} }
Future<void> setLabelForAccount({int accountIndex, String label}) async { Future<void> setLabelForAccount({required int accountIndex, required String label}) async {
await compute( await compute(
_setLabelForAccount, {'accountIndex': accountIndex, 'label': label}); _setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
await store(); await store();

View file

@ -1,8 +1,8 @@
import 'dart:ffi'; import 'dart:ffi';
import 'package:ffi/ffi.dart'; import 'package:ffi/ffi.dart';
String convertUTF8ToString({Pointer<Utf8> pointer}) { String convertUTF8ToString({required Pointer<Utf8> pointer}) {
final str = Utf8.fromUtf8(pointer); final str = pointer.toDartString();
free(pointer); calloc.free(pointer);
return str; return str;
} }

View file

@ -8,7 +8,7 @@ class CwHaven {
const MethodChannel('cw_haven'); const MethodChannel('cw_haven');
static Future<String> get platformVersion async { static Future<String> get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion'); final String version = await _channel.invokeMethod<String>('getPlatformVersion') ?? '';
return version; return version;
} }
} }

Some files were not shown because too many files have changed in this diff Show more