diff --git a/lib/providers/generate_wallets.dart b/lib/providers/generate_wallets.dart index d4560d0..5b9c5f7 100644 --- a/lib/providers/generate_wallets.dart +++ b/lib/providers/generate_wallets.dart @@ -10,6 +10,7 @@ import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/providers/substrate_sdk.dart'; import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; +import 'package:polkawallet_sdk/api/apiKeyring.dart'; import 'package:provider/provider.dart'; import "package:unorm_dart/unorm_dart.dart" as unorm; @@ -21,6 +22,7 @@ class GenerateWalletsProvider with ChangeNotifier { FocusNode walletNameFocus = FocusNode(); Color? askedWordColor = Colors.black; bool isAskedWordValid = false; + int scanedWalletNumber = -1; late int nbrWord; String? nbrWordAlpha; @@ -55,8 +57,7 @@ class GenerateWalletsProvider with ChangeNotifier { TextEditingController cellController11 = TextEditingController(); bool isFirstTimeSentenceComplete = true; - Future storeHDWChest( - String address, String _name, BuildContext context) async { + Future storeHDWChest(BuildContext context) async { int chestNumber = chestBox.isEmpty ? 0 : chestBox.keys.last + 1; String chestName; @@ -75,16 +76,6 @@ class GenerateWalletsProvider with ChangeNotifier { await chestBox.add(thisChest); int? chestKey = chestBox.keys.last; - WalletData myWallet = WalletData( - version: dataVersion, - chest: chestKey, - address: address, - number: 0, - name: _name, - derivation: 2, - imageDefaultPath: '0.png'); - await walletBox.add(myWallet); - await configBox.put('currentChest', chestKey); notifyListeners(); } @@ -271,13 +262,25 @@ class GenerateWalletsProvider with ChangeNotifier { return _wordsList; } - bool isBipWord(String word) { + bool isBipWord(String word, [bool checkRedondance = true]) { + bool isValid = false; notifyListeners(); // Needed for bad encoding of UTF-8 word = word.replaceAll('é', 'é'); word = word.replaceAll('è', 'è'); - return bip39Words(appLang).contains(word.toLowerCase()); + + int nbrMatch = 0; + if (bip39Words(appLang).contains(word.toLowerCase())) { + for (var bipWord in bip39Words(appLang)) { + if (bipWord.startsWith(word)) { + isValid = nbrMatch == 0 ? true : false; + if (checkRedondance) nbrMatch = nbrMatch + 1; + } + } + } + + return isValid; } bool isBipWordsList(List words) { @@ -349,7 +352,7 @@ class GenerateWalletsProvider with ChangeNotifier { cellController11 ]; for (var word in sentence!.text!.split(' ')) { - bool isValid = isBipWord(word); + bool isValid = isBipWord(word, false); if (isValid) { cells[nbr].text = word; @@ -361,4 +364,84 @@ class GenerateWalletsProvider with ChangeNotifier { void reloadBuild() { notifyListeners(); } + + Future scanDerivations(BuildContext context, + {int numberScan = 20}) async { + SubstrateSdk _sub = Provider.of(context, listen: false); + final ss58 = _sub.ss58; + final currentChestNumber = configBox.get('currentChest'); + bool isAlive = false; + scanedWalletNumber = 0; + notifyListeners(); + + final hasRoot = await scanRootBalance(_sub, currentChestNumber); + if (hasRoot) { + scanedWalletNumber = 1; + isAlive = true; + } + + for (var derivationNbr in [for (var i = 0; i < numberScan; i += 1) i]) { + final addressData = await _sub.sdk.api.keyring.addressFromMnemonic(ss58, + cryptoType: CryptoType.sr25519, + mnemonic: generatedMnemonic!, + derivePath: '//$derivationNbr'); + + final balance = await _sub.getBalance(addressData.address!); + + log.d(balance); + if (balance != 0) { + isAlive = true; + String walletName = scanedWalletNumber == 0 + ? 'Mon portefeuille courant' + : 'Portefeuille ${scanedWalletNumber + 1}'; + await _sub.importAccount( + mnemonic: '', + fromMnemonic: true, + derivePath: '//$derivationNbr', + password: pin.text); + + WalletData myWallet = WalletData( + version: dataVersion, + chest: currentChestNumber, + address: addressData.address!, + number: scanedWalletNumber, + name: walletName, + derivation: derivationNbr, + imageDefaultPath: '${scanedWalletNumber % 4}.png'); + await walletBox.add(myWallet); + scanedWalletNumber = scanedWalletNumber + 1; + } + } + scanedWalletNumber = -1; + notifyListeners(); + return isAlive; + } + + Future scanRootBalance( + SubstrateSdk _sub, int currentChestNumber) async { + final addressData = await _sub.sdk.api.keyring.addressFromMnemonic(ss58, + cryptoType: CryptoType.sr25519, mnemonic: generatedMnemonic!); + + final balance = await _sub.getBalance(addressData.address!); + + log.d(balance); + if (balance != 0) { + String walletName = 'Mon portefeuille racine'; + await _sub.importAccount( + mnemonic: '', fromMnemonic: true, password: pin.text); + + WalletData myWallet = WalletData( + version: dataVersion, + chest: currentChestNumber, + address: addressData.address!, + number: 0, + name: walletName, + derivation: -1, + imageDefaultPath: '0.png'); + await walletBox.add(myWallet); + return true; + } else { + return false; + } + } } diff --git a/lib/screens/myWallets/restore_chest.dart b/lib/screens/myWallets/restore_chest.dart index 212e7b3..2dc935d 100644 --- a/lib/screens/myWallets/restore_chest.dart +++ b/lib/screens/myWallets/restore_chest.dart @@ -102,8 +102,10 @@ class RestoreChest extends StatelessWidget { context, FaderTransition( page: skipIntro - ? const OnboardingStepNine() - : const OnboardingStepSeven(), + ? const OnboardingStepNine( + scanDerivation: true) + : const OnboardingStepSeven( + scanDerivation: true), isFast: true), ); } else { @@ -123,24 +125,32 @@ class RestoreChest extends StatelessWidget { Column(children: [ const SizedBox(height: 20), SizedBox( - width: 150, - height: 50, + width: 190, + height: 60, child: ElevatedButton( - style: ElevatedButton.styleFrom( - elevation: 4, - primary: yellowC, // background - onPrimary: Colors.black, // foreground - ), - onPressed: () { - genW.pasteMnemonic(context); - }, - child: const Text( - 'Coller depuis le\npresse-papier', - textAlign: TextAlign.center, - style: - TextStyle(fontSize: 16, fontWeight: FontWeight.w400), - ), - ), + style: ElevatedButton.styleFrom( + elevation: 4, + primary: yellowC, // background + onPrimary: Colors.black, // foreground + ), + onPressed: () { + genW.pasteMnemonic(context); + }, + child: Row( + children: const [ + Icon( + Icons.content_paste_go, + size: 25, + ), + SizedBox(width: 10), + Text( + 'Coller depuis le\npresse-papier', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 17, fontWeight: FontWeight.w400), + ), + ], + )), ) ]) ]), diff --git a/lib/screens/onBoarding/10.dart b/lib/screens/onBoarding/10.dart index a00e5d0..d2e756d 100644 --- a/lib/screens/onBoarding/10.dart +++ b/lib/screens/onBoarding/10.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; +import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/providers/generate_wallets.dart'; import 'package:gecko/providers/my_wallets.dart'; import 'package:gecko/providers/substrate_sdk.dart'; @@ -15,10 +16,10 @@ import 'package:provider/provider.dart'; // ignore: must_be_immutable class OnboardingStepTen extends StatelessWidget { - OnboardingStepTen({ - Key? validationKey, - }) : super(key: validationKey); + OnboardingStepTen({Key? validationKey, this.scanDerivation = false}) + : super(key: validationKey); + final bool scanDerivation; final formKey = GlobalKey(); Color? pinColor = const Color(0xFFA4B600); bool hasError = false; @@ -58,6 +59,20 @@ class OnboardingStepTen extends StatelessWidget { style: TextStyle(fontSize: 16 * ratio)) ]), SizedBox(height: isTall ? 80 : 20), + Visibility( + visible: _generateWalletProvider.scanedWalletNumber != -1, + child: Padding( + padding: const EdgeInsets.only(bottom: 15), + child: SizedBox( + height: 22, + width: 22, + child: CircularProgressIndicator( + color: orangeC, + strokeWidth: 3, + ), + ), + ), + ), pinForm(context, _walletOptions, _pinLenght, 1, 2), InkWell( onTap: () { @@ -153,18 +168,32 @@ class OnboardingStepTen extends StatelessWidget { log.d(_pin + ' || ' + _generateWalletProvider.pin.text); if (_pin.toUpperCase() == _generateWalletProvider.pin.text) { pinColor = Colors.green[500]; - final address = await _sub.importAccount( - fromMnemonic: true, - mnemonic: _generateWalletProvider.generatedMnemonic!, - derivePath: '//2', - password: _generateWalletProvider.pin.text); - await _generateWalletProvider.storeHDWChest( - address, 'Mon portefeuille courant', context); + + await _generateWalletProvider.storeHDWChest(context); + bool isAlive = false; + if (scanDerivation) { + isAlive = await _generateWalletProvider + .scanDerivations(context, numberScan: 20); + } + if (!isAlive) { + final address = await _sub.importAccount( + fromMnemonic: true, + mnemonic: _generateWalletProvider.generatedMnemonic!, + derivePath: '//2', + password: _generateWalletProvider.pin.text); + WalletData myWallet = WalletData( + version: dataVersion, + chest: configBox.get('currentChest'), + address: address, + number: 0, + name: 'Mon portefeuille courant', + derivation: 2, + imageDefaultPath: '0.png'); + await walletBox.add(myWallet); + } _myWalletProvider.readAllWallets(_currentChest); - // scheduleMicrotask(() { - // _walletOptions.reloadBuild(); _myWalletProvider.rebuildWidget(); - // }); + _generateWalletProvider.generatedMnemonic = ''; _myWalletProvider.resetPinCode(); Navigator.push( diff --git a/lib/screens/onBoarding/7.dart b/lib/screens/onBoarding/7.dart index b430bf0..676331a 100644 --- a/lib/screens/onBoarding/7.dart +++ b/lib/screens/onBoarding/7.dart @@ -6,7 +6,8 @@ import 'package:gecko/screens/common_elements.dart'; import 'package:gecko/screens/onBoarding/8.dart'; class OnboardingStepSeven extends StatelessWidget { - const OnboardingStepSeven({Key? key}) : super(key: key); + const OnboardingStepSeven({Key? key, this.scanDerivation = false}) : super(key: key); + final bool scanDerivation; @override Widget build(BuildContext context) { @@ -35,7 +36,7 @@ class OnboardingStepSeven extends StatelessWidget { ], 'coffre-fort-code-secret-dans-telephone.png', '>', - const OnboardingStepEight(), + OnboardingStepEight(scanDerivation: scanDerivation), 6, boxHeight: 400), ), diff --git a/lib/screens/onBoarding/8.dart b/lib/screens/onBoarding/8.dart index 4bcb744..0b6555f 100644 --- a/lib/screens/onBoarding/8.dart +++ b/lib/screens/onBoarding/8.dart @@ -6,7 +6,9 @@ import 'package:gecko/screens/common_elements.dart'; import 'package:gecko/screens/onBoarding/9.dart'; class OnboardingStepEight extends StatelessWidget { - const OnboardingStepEight({Key? key}) : super(key: key); + const OnboardingStepEight({Key? key, this.scanDerivation = false}) + : super(key: key); + final bool scanDerivation; @override Widget build(BuildContext context) { @@ -41,7 +43,7 @@ class OnboardingStepEight extends StatelessWidget { ], 'coffre-fort-protege-les-portefeuilles.png', '>', - const OnboardingStepNine(), + OnboardingStepNine(scanDerivation: scanDerivation), 7), ), ); diff --git a/lib/screens/onBoarding/9.dart b/lib/screens/onBoarding/9.dart index 5dda878..16dbda0 100644 --- a/lib/screens/onBoarding/9.dart +++ b/lib/screens/onBoarding/9.dart @@ -9,7 +9,9 @@ import 'package:provider/provider.dart'; // ignore: must_be_immutable class OnboardingStepNine extends StatelessWidget { - const OnboardingStepNine({Key? key}) : super(key: key); + const OnboardingStepNine({Key? key, this.scanDerivation = false}) + : super(key: key); + final bool scanDerivation; @override Widget build(BuildContext context) { @@ -103,7 +105,7 @@ class OnboardingStepNine extends StatelessWidget { ))), SizedBox(height: 22 * ratio), common.nextButton(context, "J'ai noté mon code secret", - OnboardingStepTen(), false), + OnboardingStepTen(scanDerivation: scanDerivation), false), SizedBox(height: 35 * ratio), ]), ));