From 8e49ac73ff9e994737c9079e076ba964508f0c69 Mon Sep 17 00:00:00 2001 From: poka Date: Wed, 1 Jun 2022 15:17:07 +0200 Subject: [PATCH] fix: chest change not consistent; feat: Can create custom derivation number, and root wallet --- lib/main.dart | 3 + lib/providers/generate_wallets.dart | 7 +- lib/providers/my_wallets.dart | 92 ++++++++-- lib/providers/substrate_sdk.dart | 20 ++- lib/screens/myWallets/chest_options.dart | 34 +++- lib/screens/myWallets/custom_derivations.dart | 161 ++++++++++++++++++ lib/screens/myWallets/unlocking_wallet.dart | 5 - pubspec.yaml | 2 +- 8 files changed, 292 insertions(+), 32 deletions(-) create mode 100644 lib/screens/myWallets/custom_derivations.dart diff --git a/lib/main.dart b/lib/main.dart index 9ae1493..586c971 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -74,6 +74,9 @@ Future main() async { await _homeProvider.getValidEndpoints(); // await configBox.delete('isCacheChecked'); + if (configBox.get('isCacheChecked') == null) { + configBox.put('isCacheChecked', false); + } // log.d(await configBox.get('endpoint')); HttpOverrides.global = MyHttpOverrides(); diff --git a/lib/providers/generate_wallets.dart b/lib/providers/generate_wallets.dart index 763fc93..350d5b3 100644 --- a/lib/providers/generate_wallets.dart +++ b/lib/providers/generate_wallets.dart @@ -57,12 +57,7 @@ class GenerateWalletsProvider with ChangeNotifier { Future storeHDWChest( String address, String _name, BuildContext context) async { - int chestNumber = 0; - chestBox.toMap().forEach((key, value) { - if (!value.isCesium!) { - chestNumber++; - } - }); + int chestNumber = chestBox.isEmpty ? 0 : chestBox.keys.last + 1; String chestName; if (chestNumber == 0) { diff --git a/lib/providers/my_wallets.dart b/lib/providers/my_wallets.dart index c058ec4..b48bafb 100644 --- a/lib/providers/my_wallets.dart +++ b/lib/providers/my_wallets.dart @@ -30,7 +30,8 @@ class MyWalletsProvider with ChangeNotifier { } } - List readAllWallets(int? _chest) { + List readAllWallets([int? _chest]) { + _chest = _chest ?? configBox.get('currentChest') ?? 0; listWallets.clear(); walletBox.toMap().forEach((key, value) { if (value.chest == _chest) { @@ -108,28 +109,20 @@ class MyWalletsProvider with ChangeNotifier { } } - Future generateNewDerivation(context, String _name) async { - MyWalletsProvider _myWalletProvider = - Provider.of(context, listen: false); - + Future generateNewDerivation(context, String _name, + [int? number]) async { isNewDerivationLoading = true; notifyListeners(); - int _newDerivationNbr; - int _newWalletNbr; + + final List idList = getNextWalletNumberAndDerivation(); + int _newWalletNbr = idList[0]; + int _newDerivationNbr = number ?? idList[1]; + int? _chest = getCurrentChest(); - List _walletConfig = readAllWallets(_chest); - - if (_walletConfig.isEmpty) { - _newDerivationNbr = 2; - _newWalletNbr = 0; - } else { - _newDerivationNbr = _walletConfig.last.derivation! + 2; - _newWalletNbr = _walletConfig.last.number! + 1; - } SubstrateSdk _sub = Provider.of(context, listen: false); - WalletData defaultWallet = _myWalletProvider.getDefaultWallet()!; + WalletData defaultWallet = getDefaultWallet()!; final address = await _sub.derive( context, defaultWallet.address!, _newDerivationNbr, pinCode); @@ -149,6 +142,71 @@ class MyWalletsProvider with ChangeNotifier { notifyListeners(); } + Future generateRootWallet(context, String _name) async { + MyWalletsProvider _myWalletProvider = + Provider.of(context, listen: false); + + isNewDerivationLoading = true; + notifyListeners(); + int _newWalletNbr; + int? _chest = getCurrentChest(); + + List _walletConfig = readAllWallets(_chest); + + if (_walletConfig.isEmpty) { + _newWalletNbr = 0; + } else { + _newWalletNbr = _walletConfig.last.number! + 1; + } + SubstrateSdk _sub = Provider.of(context, listen: false); + + WalletData defaultWallet = _myWalletProvider.getDefaultWallet()!; + + final address = + await _sub.generateRootKeypair(defaultWallet.address!, pinCode); + + WalletData newWallet = WalletData( + version: dataVersion, + chest: _chest, + address: address, + number: _newWalletNbr, + name: _name, + derivation: -1, + imageDefaultPath: '${_newWalletNbr % 4}.png'); + + await walletBox.add(newWallet); + + isNewDerivationLoading = false; + notifyListeners(); + } + + List getNextWalletNumberAndDerivation( + {int? chestNumber, bool isOneshoot = false}) { + int _newDerivationNbr = 0; + int _newWalletNbr = 0; + + chestNumber ??= getCurrentChest(); + + List _walletConfig = readAllWallets(chestNumber); + + if (_walletConfig.isEmpty) { + _newDerivationNbr = 2; + } else { + WalletData _lastWallet = _walletConfig.reduce( + (curr, next) => curr.derivation! > next.derivation! ? curr : next); + + if (_lastWallet.derivation == -1) { + _newDerivationNbr = 2; + } else { + _newDerivationNbr = _lastWallet.derivation! + (isOneshoot ? 1 : 2); + } + + _newWalletNbr = _walletConfig.last.number! + 1; + } + + return [_newWalletNbr, _newDerivationNbr]; + } + int lockPin = 0; Future resetPinCode([int minutes = 15]) async { lockPin++; diff --git a/lib/providers/substrate_sdk.dart b/lib/providers/substrate_sdk.dart index 6bee52c..9863596 100644 --- a/lib/providers/substrate_sdk.dart +++ b/lib/providers/substrate_sdk.dart @@ -230,6 +230,8 @@ class SubstrateSdk with ChangeNotifier { Future checkPassword(String address, String pass) async { final account = getKeypair(address); + // log.d(account.address); + return await sdk.api.keyring.checkPassword(account, pass); } @@ -510,7 +512,23 @@ class SubstrateSdk with ChangeNotifier { generatedMnemonic = seedList[0]; return await importAccount( - fromMnemonic: true, derivePath: '//$number', password: password); + mnemonic: generatedMnemonic, + fromMnemonic: true, + derivePath: '//$number', + password: password); + } + + Future generateRootKeypair(String address, String password) async { + final keypair = getKeypair(address); + + final seedMap = + await keyring.store.getDecryptedSeed(keypair.pubKey, password); + + if (seedMap?['type'] != 'mnemonic') return ''; + final List seedList = seedMap!['seed'].split('//'); + generatedMnemonic = seedList[0]; + + return await importAccount(fromMnemonic: true, password: password); } Future isMnemonicValid(String mnemonic) async { diff --git a/lib/screens/myWallets/chest_options.dart b/lib/screens/myWallets/chest_options.dart index cffe800..9cb75b5 100644 --- a/lib/screens/myWallets/chest_options.dart +++ b/lib/screens/myWallets/chest_options.dart @@ -7,6 +7,7 @@ import 'package:gecko/providers/chest_provider.dart'; import 'package:gecko/providers/home.dart'; import 'package:gecko/providers/my_wallets.dart'; import 'package:gecko/screens/myWallets/change_pin.dart'; +import 'package:gecko/screens/myWallets/custom_derivations.dart'; import 'package:gecko/screens/myWallets/show_seed.dart'; import 'package:gecko/screens/myWallets/unlocking_wallet.dart'; import 'package:provider/provider.dart'; @@ -123,7 +124,7 @@ class ChestOptions extends StatelessWidget { child: SizedBox( height: 50, child: Row(children: [ - const SizedBox(width: 28), + const SizedBox(width: 26), Image.asset( 'assets/chests/secret_code.png', height: 25, @@ -136,6 +137,35 @@ class ChestOptions extends StatelessWidget { ])), ), SizedBox(height: 10 * ratio), + InkWell( + key: const Key('createRootDerivation'), + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const CustomDerivation(); + }, + ), + ); + }, + child: SizedBox( + height: 50, + child: Row(children: const [ + SizedBox(width: 35), + Icon( + Icons.manage_accounts, + size: 33, + ), + SizedBox(width: 25), + Text( + 'Créer une autre dérivation', + style: TextStyle(fontSize: 20, color: Colors.black), + ), + ]), + ), + ), + SizedBox(height: 10 * ratio), InkWell( key: const Key('deleteChest'), onTap: () async { @@ -144,7 +174,7 @@ class ChestOptions extends StatelessWidget { child: SizedBox( height: 50, child: Row(children: [ - const SizedBox(width: 30), + const SizedBox(width: 28), Image.asset( 'assets/walletOptions/trash.png', height: 45, diff --git a/lib/screens/myWallets/custom_derivations.dart b/lib/screens/myWallets/custom_derivations.dart new file mode 100644 index 0000000..2d2f46e --- /dev/null +++ b/lib/screens/myWallets/custom_derivations.dart @@ -0,0 +1,161 @@ +import 'package:flutter/services.dart'; +import 'package:gecko/globals.dart'; +import 'package:flutter/material.dart'; +import 'package:gecko/models/wallet_data.dart'; +import 'package:gecko/providers/my_wallets.dart'; +import 'package:gecko/screens/myWallets/unlocking_wallet.dart'; +import 'package:provider/provider.dart'; + +class CustomDerivation extends StatefulWidget { + const CustomDerivation({Key? key}) : super(key: key); + + @override + State createState() => _CustomDerivationState(); +} + +class _CustomDerivationState extends State { + String? dropdownValue; + + @override + void initState() { + dropdownValue = 'root'; + super.initState(); + } + + @override + Widget build(BuildContext context) { + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + MyWalletsProvider _myWalletProvider = + Provider.of(context, listen: false); + + final derivationList = [ + 'root', + for (var i = 0; i < 50; i += 1) i.toString() + ]; + + final listWallets = _myWalletProvider.readAllWallets(); + + for (WalletData _wallet in listWallets) { + derivationList.remove(_wallet.derivation.toString()); + if (_wallet.derivation == -1) { + derivationList.remove('root'); + } + } + + if (!derivationList.contains(dropdownValue)) { + dropdownValue = derivationList.first; + } + + return Scaffold( + backgroundColor: backgroundColor, + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text('Créer une dérivation personnalisé'), + )), + body: Center( + child: SafeArea( + child: Column(children: [ + const Spacer(), + const Text( + 'Choisissez une dérivation:', + ), + const SizedBox(height: 20), + SizedBox( + width: 100, + child: DropdownButton( + value: dropdownValue, + menuMaxHeight: 300, + icon: const Icon(Icons.arrow_downward), + elevation: 16, + style: TextStyle(color: orangeC), + underline: Container( + height: 2, + color: orangeC, + ), + onChanged: (String? newValue) { + setState(() { + dropdownValue = newValue!; + }); + }, + items: derivationList + .map>((String value) { + return DropdownMenuItem( + value: value, + child: SizedBox( + width: 75, + child: Row(children: [ + const Spacer(), + Text( + value, + style: const TextStyle( + fontSize: 20, color: Colors.black), + ), + const Spacer(), + ]), + )); + }).toList(), + ), + ), + const Spacer(flex: 1), + SizedBox( + width: 410, + height: 70, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 4, + primary: orangeC, // background + onPrimary: Colors.white, // foreground + ), + onPressed: () async { + WalletData? defaultWallet = + _myWalletProvider.getDefaultWallet(); + String? _pin; + if (_myWalletProvider.pinCode == '') { + _pin = await Navigator.push( + context, + MaterialPageRoute( + builder: (homeContext) { + return UnlockingWallet(wallet: defaultWallet); + }, + ), + ); + } + + if (_pin != null || _myWalletProvider.pinCode != '') { + String _newDerivationName = + 'Portefeuille ${_myWalletProvider.listWallets.last.number! + 2}'; + if (dropdownValue == 'root') { + await _myWalletProvider.generateRootWallet( + context, 'Portefeuille racine'); + } else { + await _myWalletProvider.generateNewDerivation( + context, + _newDerivationName, + int.parse(dropdownValue!), + ); + } + Navigator.pop(context); + Navigator.pop(context); + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) { + // return const WalletsHome(); + // }), + // ); + } + }, + child: const Text( + 'Valider', + style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600), + ), + ), + ), + const Spacer(), + ]), + ), + ), + ); + } +} diff --git a/lib/screens/myWallets/unlocking_wallet.dart b/lib/screens/myWallets/unlocking_wallet.dart index 0237aa3..249ce71 100644 --- a/lib/screens/myWallets/unlocking_wallet.dart +++ b/lib/screens/myWallets/unlocking_wallet.dart @@ -37,10 +37,6 @@ class UnlockingWallet extends StatelessWidget { currentChestNumber = configBox.get('currentChest'); currentChest = chestBox.get(currentChestNumber)!; - if (configBox.get('isCacheChecked') == null) { - configBox.put('isCacheChecked', false); - } - int _pinLenght = _walletOptions.getPinLenght(wallet!.number); errorController = StreamController(); @@ -222,7 +218,6 @@ class UnlockingWallet extends StatelessWidget { ], onCompleted: (_pin) async { _myWalletProvider.pinCode = _pin.toUpperCase(); - final isValid = await _sub.checkPassword( defaultWallet!.address!, _pin.toUpperCase()); diff --git a/pubspec.yaml b/pubspec.yaml index 05e18bd..563fb9c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ description: Pay with G1. # pub.dev using `pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 0.0.7+9 +version: 0.0.7+10 environment: sdk: '>=2.12.0 <3.0.0'