diff --git a/assets/translations/en.json b/assets/translations/en.json index 87d92a1..81e472f 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -178,5 +178,11 @@ "derivationsScanProgress": "Scan address {}/{}", "youAreOffline": "You are offline...", "importG1v1": "Import old G1v1 account", - "selectDestWallet": "Select a target wallet:" + "selectDestWallet": "Select a target wallet:", + "youMustWaitBeforeCashoutThisAccount": "You have to wait {} minutes\nbefore migrate this account", + "thisAccountIsEmpty": "This account is empty", + "youCannotMigrateIdentityToExistingIdentity": "You cannot migrate an identity\nto an account that already has an identity", + "importOldAccount": "Import your old account", + "enterCesiumId": "Enter your Cesium ID", + "enterCesiumPassword": "Enter your Cesium password" } \ No newline at end of file diff --git a/assets/translations/es.json b/assets/translations/es.json index ab3fb87..567af90 100644 --- a/assets/translations/es.json +++ b/assets/translations/es.json @@ -178,5 +178,11 @@ "derivationsScanProgress": "Scan address {}/{}", "youAreOffline": "You are offline...", "importG1v1": "Import old G1v1 account", - "selectDestWallet": "Select a target wallet:" + "selectDestWallet": "Select a target wallet:", + "youMustWaitBeforeCashoutThisAccount": "You have to wait {} minutes\nbefore migrate this account", + "thisAccountIsEmpty": "This account is empty", + "youCannotMigrateIdentityToExistingIdentity": "You cannot migrate an identity\nto an account that already has an identity", + "importOldAccount": "Import your old account", + "enterCesiumId": "Enter your Cesium ID", + "enterCesiumPassword": "Enter your Cesium password" } \ No newline at end of file diff --git a/assets/translations/fr.json b/assets/translations/fr.json index be333dc..b22d86b 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -179,5 +179,11 @@ "derivationsScanProgress": "Scan de l'adresse {}/{}", "youAreOffline": "Vous êtes hors ligne...", "importG1v1": "Importer son compte G1v1", - "selectDestWallet": "Sélectionner un portefeuille cible:" + "selectDestWallet": "Sélectionnez un portefeuille cible:", + "youMustWaitBeforeCashoutThisAccount": "Vous devez attendre {} minutes\navant de pouvoir migrer ce compte", + "thisAccountIsEmpty": "Ce compte est vide", + "youCannotMigrateIdentityToExistingIdentity": "Vous ne pouvez pas migrer une identité\nvers un compte disposant déjà d'une identité", + "importOldAccount": "Importer son ancien compte", + "enterCesiumId": "Entrez votre identifiant Cesium", + "enterCesiumPassword": "Entrez votre mot de passe Cesium" } \ No newline at end of file diff --git a/lib/providers/substrate_sdk.dart b/lib/providers/substrate_sdk.dart index dde57f3..d42a865 100644 --- a/lib/providers/substrate_sdk.dart +++ b/lib/providers/substrate_sdk.dart @@ -252,7 +252,7 @@ class SubstrateSdk with ChangeNotifier { return certMeta; } - Future idtyStatus(String address, [bool smooth = true]) async { + Future idtyStatus(String address) async { var idtyIndex = await getIdentityIndexOf(address); if (idtyIndex == 0) { @@ -297,6 +297,11 @@ class SubstrateSdk with ChangeNotifier { log.i('currencyParameters: $currencyParameters'); } + void cesiumIDisVisible() { + isCesiumIDVisible = !isCesiumIDVisible; + notifyListeners(); + } + ///////////////////////////////////// ////// 3: SUBSTRATE CONNECTION ////// ///////////////////////////////////// @@ -540,8 +545,6 @@ class SubstrateSdk with ChangeNotifier { BuildContext context, String address, int number, String password) async { final keypair = getKeypair(address); - log.d('tatatata $address $number $password ${keypair.encoded}'); - final seedMap = await keyring.store.getDecryptedSeed(keypair.pubKey, password); @@ -620,6 +623,24 @@ class SubstrateSdk with ChangeNotifier { notifyListeners(); } + Future getBalanceAndIdtyStatus(String address, String myAddress) async { + final balance = + address == '' ? {'transferableBalance': 0} : await getBalance(address); + final thisIdtyStatus = address == '' ? 'noid' : await idtyStatus(address); + final thisHasConsumer = + address == '' ? false : await hasAccountConsumers(address); + final myIdtyStatus = await idtyStatus(myAddress); + + log.d('tatata: $myIdtyStatus'); + + return [ + balance['transferableBalance'], + thisIdtyStatus, + myIdtyStatus, + thisHasConsumer + ]; + } + ////////////////////////////////////// ///////// 5: CALLS EXECUTION ///////// ////////////////////////////////////// @@ -785,9 +806,46 @@ class SubstrateSdk with ChangeNotifier { return await executeCall(txInfo, txOptions, password); } - void cesiumIDisVisible() { - isCesiumIDVisible = !isCesiumIDVisible; - notifyListeners(); + Future migrateCsToV2(String salt, String password, String destAddress, + {required double balance, String idtyStatus = 'noid'}) async { + final scrypt = pc.KeyDerivator('scrypt'); + + scrypt.init( + pc.ScryptParameters( + 4096, + 16, + 1, + 32, + Uint8List.fromList(salt.codeUnits), + ), + ); + final rawSeed = scrypt.process(Uint8List.fromList(password.codeUnits)); + final rawSeedHex = '0x${HEX.encode(rawSeed)}'; + + final json = await sdk.api.keyring.importAccount(keyring, + keyType: KeyType.rawSeed, + key: rawSeedHex, + name: 'test', + password: 'password', + derivePath: '', + cryptoType: CryptoType.ed25519); + + final keypair = await sdk.api.keyring.addAccount( + keyring, + keyType: KeyType.rawSeed, + acc: json!, + password: password, + ); + + if (balance != 0) { + await pay( + fromAddress: keypair.address!, + destAddress: destAddress, + amount: -1, + password: 'password'); + } + + await sdk.api.keyring.deleteAccount(keyring, keypair); } void reload() { diff --git a/lib/providers/wallet_options.dart b/lib/providers/wallet_options.dart index fa0c421..63a4a2d 100644 --- a/lib/providers/wallet_options.dart +++ b/lib/providers/wallet_options.dart @@ -30,6 +30,7 @@ class WalletOptionsProvider with ChangeNotifier { TextEditingController nameController = TextEditingController(); late bool isDefaultWallet; bool canValidateNameBool = false; + Map idtyStatusCache = {}; Future? get badWallet => null; @@ -157,6 +158,7 @@ class WalletOptionsProvider with ChangeNotifier { future: sub.idtyStatus(address), initialData: '', builder: (context, snapshot) { + idtyStatusCache[address] = snapshot.data.toString(); switch (snapshot.data.toString()) { case 'noid': { diff --git a/lib/screens/myWallets/import_g1_v1.dart b/lib/screens/myWallets/import_g1_v1.dart index 7557d49..7892d3b 100644 --- a/lib/screens/myWallets/import_g1_v1.dart +++ b/lib/screens/myWallets/import_g1_v1.dart @@ -4,9 +4,11 @@ import 'package:easy_localization/easy_localization.dart'; 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/providers/substrate_sdk.dart'; import 'package:gecko/providers/wallet_options.dart'; +import 'package:gecko/screens/transaction_in_progress.dart'; import 'package:provider/provider.dart'; class ImportG1v1 extends StatelessWidget { @@ -23,134 +25,234 @@ class ImportG1v1 extends StatelessWidget { Timer? debounce; const int debouneTime = 300; - String selectedWallet = myWalletProvider.getDefaultWallet().name!; + WalletData selectedWallet = myWalletProvider.getDefaultWallet(); + bool canValidate = false; + String validationStatus = ''; - return Scaffold( + return WillPopScope( + onWillPop: () { + resetScreen(context); + return Future.value(true); + }, + child: Scaffold( backgroundColor: backgroundColor, appBar: AppBar( toolbarHeight: 60 * ratio, - title: const SizedBox( - height: 22, - child: Text('Importer son ancien compte'), - )), - body: - SafeArea(child: Consumer(builder: (context, sub, _) { - return Column(children: [ - const SizedBox(height: 20), - TextFormField( - autofocus: true, - onChanged: (text) { - if (debounce?.isActive ?? false) { - debounce!.cancel(); - } - debounce = Timer(const Duration(milliseconds: debouneTime), () { - sub.csToV2Address(sub.csSalt.text, sub.csPassword.text); - }); - }, - keyboardType: TextInputType.text, - controller: sub.csSalt, - obscureText: - sub.isCesiumIDVisible, //This will obscure text dynamically - decoration: InputDecoration( - hintText: 'Entrez votre identifiant Cesium', - suffixIcon: IconButton( - icon: Icon( - sub.isCesiumIDVisible - ? Icons.visibility - : Icons.visibility_off, - color: Colors.black, - ), - onPressed: () { - sub.cesiumIDisVisible(); - }, - ), - ), - ), - const SizedBox(height: 20), - TextFormField( - autofocus: true, - onChanged: (text) { - if (debounce?.isActive ?? false) { - debounce!.cancel(); - } - debounce = Timer(const Duration(milliseconds: debouneTime), () { - sub.csToV2Address(sub.csSalt.text, sub.csPassword.text); - }); - }, - keyboardType: TextInputType.text, - controller: sub.csPassword, - obscureText: - sub.isCesiumIDVisible, //This will obscure text dynamically - decoration: InputDecoration( - hintText: 'Entrez votre mot de passe Cesium', - suffixIcon: IconButton( - icon: Icon( - sub.isCesiumIDVisible - ? Icons.visibility - : Icons.visibility_off, - color: Colors.black, - ), - onPressed: () { - sub.cesiumIDisVisible(); - }, - ), - ), - ), - const SizedBox(height: 20), - Text( - sub.g1V1NewAddress, - style: const TextStyle( - fontSize: 14.0, - color: Colors.black, - fontWeight: FontWeight.bold, - fontFamily: 'Monospace'), - ), - const SizedBox(height: 20), - balance(context, sub.g1V1NewAddress, 17), - walletOptions.idtyStatus(context, sub.g1V1NewAddress, - isOwner: false, color: Colors.black), - getCerts(context, sub.g1V1NewAddress, 14), - const SizedBox(height: 30), - Text('selectDestWallet'.tr()), - const SizedBox(height: 10), - DropdownButtonHideUnderline( - child: DropdownButton( - // alignment: AlignmentDirectional.topStart, - value: selectedWallet, - icon: const Icon(Icons.keyboard_arrow_down), - items: myWalletProvider.listWallets.map((wallet) { - return DropdownMenuItem( - value: wallet.name, - child: Text(wallet.name!), - ); - }).toList(), - onChanged: (newSelectedWallet) { - selectedWallet = newSelectedWallet.toString(); - sub.reload(); - }, - ), - ), - const SizedBox(height: 30), - SizedBox( - width: 380 * ratio, - height: 60 * ratio, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - elevation: 4, - primary: orangeC, // background - onPrimary: Colors.white, // foreground - ), + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.black), onPressed: () { - log.d('GOOO'); - }, - child: Text( - 'validate'.tr(), - style: TextStyle( - fontSize: 23 * ratio, fontWeight: FontWeight.w600), - ), - ), - ) - ]); - }))); + resetScreen(context); + + Navigator.of(context).pop(); + }), + title: SizedBox( + height: 22, + child: Text('importOldAccount'.tr()), + )), + body: SafeArea( + child: Consumer(builder: (context, sub, _) { + return FutureBuilder( + future: sub.getBalanceAndIdtyStatus( + sub.g1V1NewAddress, selectedWallet.address!), + builder: (BuildContext context, AsyncSnapshot status) { + // log.d(_certs.data); + + final balance = status.data?[0] ?? 0; + final idtyStatus = status.data?[1]; + final myIdtyStatus = status.data?[2]; + final hasConsumer = status.data?[3] ?? false; + + if (balance != 0 && !hasConsumer) { + canValidate = true; + validationStatus = ''; + } else { + canValidate = false; + validationStatus = hasConsumer + ? 'youMustWaitBeforeCashoutThisAccount'.tr(args: ['X']) + : 'thisAccountIsEmpty'.tr(); + } + + if (idtyStatus != 'noid' && myIdtyStatus != 'noid') { + canValidate = false; + validationStatus = + 'youCannotMigrateIdentityToExistingIdentity'.tr(); + } + + if (sub.g1V1NewAddress == '') { + validationStatus = ''; + } + + log.d( + 'tatatata: ${sub.g1V1NewAddress}, ${selectedWallet.address!}, $balance, $idtyStatus, $myIdtyStatus'); + + return Column(children: [ + const SizedBox(height: 20), + TextFormField( + autofocus: true, + onChanged: (text) { + if (debounce?.isActive ?? false) { + debounce!.cancel(); + } + debounce = Timer( + const Duration(milliseconds: debouneTime), () { + sub.csToV2Address( + sub.csSalt.text, sub.csPassword.text); + }); + }, + keyboardType: TextInputType.text, + controller: sub.csSalt, + obscureText: sub + .isCesiumIDVisible, //This will obscure text dynamically + decoration: InputDecoration( + hintText: 'enterCesiumId'.tr(), + suffixIcon: IconButton( + icon: Icon( + sub.isCesiumIDVisible + ? Icons.visibility + : Icons.visibility_off, + color: Colors.black, + ), + onPressed: () { + sub.cesiumIDisVisible(); + }, + ), + ), + ), + const SizedBox(height: 20), + TextFormField( + autofocus: true, + onChanged: (text) { + if (debounce?.isActive ?? false) { + debounce!.cancel(); + } + debounce = Timer( + const Duration(milliseconds: debouneTime), () { + sub.csToV2Address( + sub.csSalt.text, sub.csPassword.text); + }); + }, + keyboardType: TextInputType.text, + controller: sub.csPassword, + obscureText: sub + .isCesiumIDVisible, //This will obscure text dynamically + decoration: InputDecoration( + hintText: 'enterCesiumPassword'.tr(), + suffixIcon: IconButton( + icon: Icon( + sub.isCesiumIDVisible + ? Icons.visibility + : Icons.visibility_off, + color: Colors.black, + ), + onPressed: () { + sub.cesiumIDisVisible(); + }, + ), + ), + ), + const SizedBox(height: 20), + Text( + sub.g1V1NewAddress, + style: const TextStyle( + fontSize: 14.0, + color: Colors.black, + fontWeight: FontWeight.bold, + fontFamily: 'Monospace'), + ), + const SizedBox(height: 20), + Text( + '$balance $currencyName', + style: const TextStyle(fontSize: 17), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + walletOptions.idtyStatus(context, sub.g1V1NewAddress, + isOwner: false, color: Colors.black), + const SizedBox(width: 10), + getCerts(context, sub.g1V1NewAddress, 14) + ], + ), + const SizedBox(height: 30), + Text('selectDestWallet'.tr()), + const SizedBox(height: 5), + DropdownButtonHideUnderline( + child: DropdownButton( + // alignment: AlignmentDirectional.topStart, + value: selectedWallet, + icon: const Icon(Icons.keyboard_arrow_down), + items: myWalletProvider.listWallets.map((wallet) { + return DropdownMenuItem( + value: wallet, + child: Text( + wallet.name!, + style: const TextStyle(fontSize: 18), + ), + ); + }).toList(), + onChanged: (WalletData? newSelectedWallet) { + selectedWallet = newSelectedWallet!; + sub.reload(); + }, + ), + ), + const SizedBox(height: 30), + SizedBox( + width: 380 * ratio, + height: 60 * ratio, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 4, + primary: orangeC, // background + onPrimary: Colors.white, // foreground + ), + onPressed: canValidate + ? () async { + log.d('GOOO'); + + sub.migrateCsToV2( + sub.csSalt.text, + sub.csPassword.text, + selectedWallet.address!, + balance: balance, + idtyStatus: idtyStatus); + + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return const TransactionInProgress(); + }), + ); + resetScreen(context); + } + : null, + child: Text( + 'validate'.tr(), + style: TextStyle( + fontSize: 23 * ratio, + fontWeight: FontWeight.w600), + ), + ), + ), + const SizedBox(height: 10), + Text( + validationStatus, + textAlign: TextAlign.center, + style: TextStyle(fontSize: 15, color: Colors.grey[600]), + ) + ]); + }); + }), + ), + ), + ); + } + + void resetScreen(BuildContext context) { + SubstrateSdk sub = Provider.of(context, listen: false); + + sub.csSalt.text = ''; + sub.csPassword.text = ''; + sub.g1V1NewAddress = ''; } }