From ad601be19ce9e40ef9b137828187c63d9bf5d22a Mon Sep 17 00:00:00 2001
From: poka <poka@p2p.legal>
Date: Sat, 20 Aug 2022 20:08:02 +0200
Subject: [PATCH] can migrate identity from standart mnemonic derivation

---
 assets/skull_Icon.png                        | Bin 0 -> 2280 bytes
 assets/translations/en.json                  |   5 +-
 assets/translations/es.json                  |   5 +-
 assets/translations/fr.json                  |   5 +-
 lib/providers/substrate_sdk.dart             |  99 ++++----
 lib/providers/wallet_options.dart            |   7 +-
 lib/screens/myWallets/import_g1_v1.dart      |  21 +-
 lib/screens/myWallets/manage_membership.dart |  50 +++-
 lib/screens/myWallets/migrate_identity.dart  | 251 +++++++++++++++++++
 lib/screens/transaction_in_progress.dart     |  23 +-
 10 files changed, 384 insertions(+), 82 deletions(-)
 create mode 100755 assets/skull_Icon.png
 create mode 100644 lib/screens/myWallets/migrate_identity.dart

diff --git a/assets/skull_Icon.png b/assets/skull_Icon.png
new file mode 100755
index 0000000000000000000000000000000000000000..3a789faff538ef15afac47e1a7651b99daf2c05c
GIT binary patch
literal 2280
zcmeAS@N?(olHy`uVBq!ia0y~yU<hYmU`XL$W?*1A@*^gefq`jmfKP}k!ziFq2r$tF
zFpe1T|Ns9*mxWXr7#QxB1o;IsFfuW-u(GjpaB^|;@bd8s2nvgciit}|N=eJe$|)!+
zDXXZeYiMfe=;|978X23InweWzTG`mzJ2*NyySTc0czXNz`uPV01_g(Pg-1k1$Hd0P
zCncw(rDtSjW#{G>6c(41mX%jj*3{P3H#9c4w6?W(bar+3^!87fIBD{fsne#<m_29S
z`~?daEnc>K<*L<d)~;K>ant54+qUo6xoh{Heftj_JapvfvEwICpE-N({Dq5`E?>EN
z?Z(Ypx9{A&cmKh|M~|O8efIpt%U7@8ynXln!^cmbzkL1n{m0K=zyJLGw`pg%HUk3#
zW0JSK%e|L*k7hG4unKs(IEF|_ZavuTEX>Nl_95TLRiv@wiVL%5Z>rtrM$X7C|4&m_
zre-WuTh{pANO?n(hmnYHaDc)5j5M)X(=rycWpr@xnr(Yu|MJG&Jo6p550?G@dx5ub
zv$>o_>CRmTGqYD%))(A<B&f!sQ}%SDTiLe<2M#fEIJ{Zr?YC;PT$~i!{~pav7pMPP
zlkw%wo%t(QTdIrM8vhd6y;N0O<gWRS3kTorvJ$;(`dzX5z)bnJcO0h^`D3dEf9ce3
zI4-x`(Z5Lf??m4Fm)3kaKTqJthI^j%wYRxv8A&uSr)5MuN>JF>wrge?n;LVL+u!31
zmd_ThW;B=BFm2+CN7hmgrrW)E5-XL&zK1t=nWD_)2TvJzi;P9MPMVyts`&D&w=GkO
z<7Sc63-28>*Ijh@#^Mo_xkARn?{a|e#Da|%5+n;wE<3o&`NG03x7jQQKbzcHE|7Am
zpx&uq%CXH1JKP_qGMzW#@M@UJ(-iHX)_g#+*OsSEL?+2#jT39LBKLC%p2`&|1|pA5
znjfm1lHf@Xbg{S0pZYW}dj7n9hR=Uz^OY4z&EK$j*WT>3-U=<57xMOndDk|wzge~S
z)8o#>4-%Um3htefth)E_EGee^WV?DN{qM%}9n%m0TNGqC=|yUNeu?RZ9<FNT1xZfU
zqWhe-Oy(;8<?MSS_f+4^1zGZ<W(?O?Y>;}jNn<u|>H2^~#tHuY+dNiyFUn!KGBfYu
zV^xJ-x#bHL=jEAY-1MBe)m$KTd5*FP&!TAVEqfdzRaw$CyxZCYr?@&FPB>NOw4rg+
z!wUveH+{Si<i7o-z#boScMX#@3v+b0%vro-tv$=K>M2*8y$w@EF9dm=l-yC{>?v#V
zC3ndgI~J)f&67>uQmXt56YWGdEnGNZlFAO3n;KOtyy`0p?3rHGEm&bGvdE}QCNaQt
zW?Y%$UCS;ng-FLv)~u@dCE~XuR_yY-800Z;Td)a#*0$g)dCOm%OIYzDdvUj|RGzxV
zskSarzFk{XeK!P^Jhdz_?OYT*VXyDS%95@3JOdd&u&RF5e34}ADmkImeqr}#%aTjm
zJMugaRP3@WYdtjkr<kkq!;RAyz5O6oJuz>)FT=XvGF8Div7n+mJU4l|X0bVD7Rjd0
zcib>l?i#<(hmJq9^KMR%UG!uFr`-Fk7n8YI9<K<olgV4Sbc$)4vr+G+yJ{Xud_fEE
z@ieZS=5<Z?VnL_9b1UlvkqeJAWURiN-r>KLX~&a`v$tm4v^YJ-Nqg!xhagwh+YfuT
ze5vJsp)0DV`KHauW7f*$TjgVZnFPn%spwuQ=9(1r>Nev^+gCSPPFlT+X7ObG>eHB_
zQ)=1nxM`}@tlthvc?;%w?dV<BS9GE;;C%Fi*k$><6>q!AhNhhedU;!mL2>o<8H_rM
z^Vcq37~nMj9(&wghqzgMYZmyw?Oq^K*}Ct_lei_PpYF-}mE_&L{e`!Q!{O`~I;-X|
z?w-}KuIj0g!MP@m6;Yo$7*|xvMzw`qi0|L5yx^?K{w~`j>rG|1R{ZG9*W+u?SKOSo
z%xBi;habbrj(1vo3Aj`D$~wdCeD1P&^~w*~FGs$*!MOj-vc8lbs%QMJ*)3b})6Dvc
z-LeHM+n8>jEjxDD{%T5+9IL9~n}m}~73>?Eq<5T___4gp=gi^-Ds8elJ4K$T2NW=u
zTgv>4jJP*%hP$IDk99<m<_Z4=57_E{X~_JO5}6n0y$Pmvg1=X|Vt{knnn=0Ihu>%O
puALV9KgRa=W9z_7{TT}%*Pohx^l{pM6LU~~?dj_0vd$@?2>`UD>rDUv

literal 0
HcmV?d00001

diff --git a/assets/translations/en.json b/assets/translations/en.json
index 3bdb47ff..d3d510ac 100644
--- a/assets/translations/en.json
+++ b/assets/translations/en.json
@@ -185,5 +185,8 @@
     "importOldAccount": "Import your old account",
     "enterCesiumId": "Enter your Cesium ID",
     "enterCesiumPassword": "Enter your Cesium password",
-    "migrateAccount": "Migrate account"
+    "migrateAccount": "Migrate account",
+    "migrateIdentity": "Migrate identity",
+    "identityMigration": "Identity migration",
+    "areYouSureMigrateIdentity": "Are you sure you want to permanently migrate identity **{}** with balance of **{}** ?"
 }
\ No newline at end of file
diff --git a/assets/translations/es.json b/assets/translations/es.json
index a081ff78..89946652 100644
--- a/assets/translations/es.json
+++ b/assets/translations/es.json
@@ -185,5 +185,8 @@
     "importOldAccount": "Import your old account",
     "enterCesiumId": "Enter your Cesium ID",
     "enterCesiumPassword": "Enter your Cesium password",
-    "migrateAccount": "Migrate account"
+    "migrateAccount": "Migrate account",
+    "migrateIdentity": "Migrate identity",
+    "identityMigration": "Identity migration",
+    "areYouSureMigrateIdentity": "Are you sure you want to permanently migrate identity **{}** with balance of **{}** ?"
 }
\ No newline at end of file
diff --git a/assets/translations/fr.json b/assets/translations/fr.json
index 43c01b47..26b93ad2 100644
--- a/assets/translations/fr.json
+++ b/assets/translations/fr.json
@@ -186,5 +186,8 @@
     "importOldAccount": "Importer son ancien compte",
     "enterCesiumId": "Entrez votre identifiant Cesium",
     "enterCesiumPassword": "Entrez votre mot de passe Cesium",
-    "migrateAccount": "Migrer le compte"
+    "migrateAccount": "Migrer le compte",
+    "migrateIdentity": "Migrer l'identité",
+    "identityMigration": "Migration de l'identité",
+    "areYouSureMigrateIdentity": "Êtes-vous certain de vouloir migrer définitivement l'identité **{}** et son solde de **{}** ?"
 }
\ No newline at end of file
diff --git a/lib/providers/substrate_sdk.dart b/lib/providers/substrate_sdk.dart
index 6f43a5ca..377dc211 100644
--- a/lib/providers/substrate_sdk.dart
+++ b/lib/providers/substrate_sdk.dart
@@ -2,7 +2,6 @@
 
 import 'dart:typed_data';
 import 'package:easy_localization/easy_localization.dart';
-import 'package:fast_base58/fast_base58.dart';
 import 'package:flutter/material.dart';
 import 'package:gecko/globals.dart';
 import 'package:gecko/models/chest_data.dart';
@@ -88,16 +87,29 @@ class SubstrateSdk with ChangeNotifier {
     );
   }
 
+  Future<String> _signMessage(
+      Uint8List message, String address, String password) async {
+    final params = SignAsExtensionParam();
+    params.msgType = "pub(bytes.sign)";
+    params.request = {
+      "address": address,
+      "data": message,
+    };
+
+    final res = await sdk.api.keyring.signAsExtension(password, params);
+    return res?.signature ?? '';
+  }
+
   ////////////////////////////////////////////
   ////////// 2: GET ONCHAIN STORAGE //////////
   ////////////////////////////////////////////
 
-  Future<int> getIdentityIndexOf(String address) async {
+  Future<int> _getIdentityIndexOf(String address) async {
     return await _getStorage('identity.identityIndexOf("$address")') ?? 0;
   }
 
   Future<List<int>> getCerts(String address) async {
-    final idtyIndex = await getIdentityIndexOf(address);
+    final idtyIndex = await _getIdentityIndexOf(address);
     final certsReceiver =
         await _getStorage('cert.storageIdtyCertMeta($idtyIndex)') ?? [];
 
@@ -105,8 +117,8 @@ class SubstrateSdk with ChangeNotifier {
   }
 
   Future<int> getCertValidityPeriod(String from, String to) async {
-    final idtyIndexFrom = await getIdentityIndexOf(from);
-    final idtyIndexTo = await getIdentityIndexOf(to);
+    final idtyIndexFrom = await _getIdentityIndexOf(from);
+    final idtyIndexTo = await _getIdentityIndexOf(to);
 
     if (idtyIndexFrom == 0 || idtyIndexTo == 0) return 0;
 
@@ -246,7 +258,7 @@ class SubstrateSdk with ChangeNotifier {
   }
 
   Future<Map> getCertMeta(String address) async {
-    var idtyIndex = await getIdentityIndexOf(address);
+    var idtyIndex = await _getIdentityIndexOf(address);
 
     final certMeta =
         await _getStorage('cert.storageIdtyCertMeta($idtyIndex)') ?? '';
@@ -255,7 +267,7 @@ class SubstrateSdk with ChangeNotifier {
   }
 
   Future<String> idtyStatus(String address) async {
-    var idtyIndex = await getIdentityIndexOf(address);
+    var idtyIndex = await _getIdentityIndexOf(address);
 
     if (idtyIndex == 0) {
       return 'noid';
@@ -287,8 +299,7 @@ class SubstrateSdk with ChangeNotifier {
     final pubkey = await sdk.api.account.decodeAddress([address]);
     final String pubkeyHex = pubkey!.keys.first;
     final pubkeyByte = HEX.decode(pubkeyHex.substring(2)) as Uint8List;
-    final pubkey58 = Base58Encode(pubkeyByte);
-    log.d('tatatatata: $pubkey58');
+    // final pubkey58 = Base58Encode(pubkeyByte);
 
     return pubkeyByte;
   }
@@ -624,22 +635,18 @@ class SubstrateSdk with ChangeNotifier {
     return g1V1NewAddress;
   }
 
-  Future<List> 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');
+  Future<List> getBalanceAndIdtyStatus(
+      String fromAddress, String toAddress) async {
+    final fromBalance = fromAddress == ''
+        ? {'transferableBalance': 0}
+        : await getBalance(fromAddress);
+    final fromIdtyStatus =
+        fromAddress == '' ? 'noid' : await idtyStatus(fromAddress);
+    final fromHasConsumer =
+        fromAddress == '' ? false : await hasAccountConsumers(fromAddress);
+    final toIdtyStatus = await idtyStatus(toAddress);
 
-    return [
-      balance['transferableBalance'],
-      thisIdtyStatus,
-      myIdtyStatus,
-      thisHasConsumer
-    ];
+    return [fromBalance, fromIdtyStatus, toIdtyStatus, fromHasConsumer];
   }
 
   //////////////////////////////////////
@@ -694,8 +701,8 @@ class SubstrateSdk with ChangeNotifier {
     final myIdtyStatus = await idtyStatus(fromAddress);
     final toIdtyStatus = await idtyStatus(toAddress);
 
-    final fromIndex = await getIdentityIndexOf(fromAddress);
-    final toIndex = await getIdentityIndexOf(toAddress);
+    final fromIndex = await _getIdentityIndexOf(fromAddress);
+    final toIndex = await _getIdentityIndexOf(toAddress);
 
     if (myIdtyStatus != 'Validated') {
       transactionStatus = 'notMember';
@@ -785,24 +792,12 @@ class SubstrateSdk with ChangeNotifier {
     return await _executeCall(txInfo, txOptions, password);
   }
 
-  Future<String> signMessage(
-      Uint8List message, String address, String password) async {
-    final params = SignAsExtensionParam();
-    params.msgType = "pub(bytes.sign)";
-    params.request = {
-      "address": address,
-      "data": message,
-    };
-
-    final res = await sdk.api.keyring.signAsExtension(password, params);
-    return res?.signature ?? '';
-  }
-
   Future<String> migrateIdentity(
       {required String fromAddress,
       required String destAddress,
-      required String formPassword,
+      required String fromPassword,
       required String destPassword,
+      required Map fromBalance,
       bool withBalance = false}) async {
     transactionStatus = '';
     final fromPubkey = await sdk.api.account.decodeAddress([fromAddress]);
@@ -818,13 +813,13 @@ class SubstrateSdk with ChangeNotifier {
     final prefix = 'icok'.codeUnits;
     final genesisHashString = await getGenesisHash();
     final genesisHash = HEX.decode(genesisHashString.substring(2)) as Uint8List;
-    final idtyIndex = int32bytes(await getIdentityIndexOf(fromAddress));
+    final idtyIndex = _int32bytes(await _getIdentityIndexOf(fromAddress));
     final oldPubkey = await addressToPubkey(fromAddress);
     final messageToSign =
         Uint8List.fromList(prefix + genesisHash + idtyIndex + oldPubkey);
     final messageToSignHex = HEX.encode(messageToSign);
     final newKeySig =
-        await signMessage(messageToSign, destAddress, destPassword);
+        await _signMessage(messageToSign, destAddress, destPassword);
 
     // messageToSign: [105, 99, 111, 107, 7, 193, 18, 255, 106, 185, 215, 208, 213, 49, 235, 229, 159, 152, 179, 83, 24, 178, 129, 59, 22, 85, 87, 115, 128, 129, 157, 56, 214, 24, 45, 153, 21, 0, 0, 0, 181, 82, 178, 99, 198, 4, 156, 190, 78, 35, 102, 137, 255, 7, 162, 31, 16, 79, 255, 132, 130, 237, 230, 222, 176, 88, 245, 217, 237, 78, 196, 239]
 
@@ -852,9 +847,10 @@ newKeySig: $newKeySig""");
       const tx1 = 'api.tx.universalDividend.claimUds()';
       final tx2 =
           'api.tx.identity.changeOwnerKey("$destAddress", "$newKeySig")';
-      const tx3 = 'api.tx.balances.transferAll(false)';
+      // const tx3 = 'api.tx.balances.transferAll(false)';
 
-      rawParams = '[[$tx1, $tx2, $tx3]]';
+      rawParams =
+          fromBalance['unclaimedUds'] == 0 ? '[[$tx2]]' : '[[$tx1, $tx2]]';
     } else {
       txInfo = TxInfoData(
         'identity',
@@ -865,11 +861,11 @@ newKeySig: $newKeySig""");
       txOptions = [destAddress, newKeySig];
     }
 
-    return await _executeCall(txInfo, txOptions, formPassword, rawParams);
+    return await _executeCall(txInfo, txOptions, fromPassword, rawParams);
   }
 
   Future revokeIdentity(String address, String password) async {
-    final idtyIndex = await getIdentityIndexOf(address);
+    final idtyIndex = await _getIdentityIndexOf(address);
 
     final sender = TxSenderData(
       keyring.current.address,
@@ -892,7 +888,7 @@ newKeySig: $newKeySig""");
 
   Future migrateCsToV2(String salt, String password, String destAddress,
       {required destPassword,
-      required double balance,
+      required Map balance,
       String idtyStatus = 'noid'}) async {
     final scrypt = pc.KeyDerivator('scrypt');
 
@@ -928,10 +924,11 @@ newKeySig: $newKeySig""");
       await migrateIdentity(
           fromAddress: keypair.address!,
           destAddress: destAddress,
-          formPassword: 'password',
+          fromPassword: 'password',
           destPassword: destPassword,
-          withBalance: true);
-    } else if (balance != 0) {
+          withBalance: true,
+          fromBalance: balance);
+    } else if (balance['transferableBalance'] != 0) {
       await pay(
           fromAddress: keypair.address!,
           destAddress: destAddress,
@@ -994,5 +991,5 @@ class PasswordException implements Exception {
   PasswordException(this.cause);
 }
 
-Uint8List int32bytes(int value) =>
+Uint8List _int32bytes(int value) =>
     Uint8List(4)..buffer.asInt32List()[0] = value;
diff --git a/lib/providers/wallet_options.dart b/lib/providers/wallet_options.dart
index 63a4a2d4..bb8a6eac 100644
--- a/lib/providers/wallet_options.dart
+++ b/lib/providers/wallet_options.dart
@@ -302,8 +302,11 @@ class WalletOptionsProvider with ChangeNotifier {
                           Navigator.push(
                             context,
                             MaterialPageRoute(builder: (context) {
-                              return const TransactionInProgress(
-                                  transType: 'comfirmIdty');
+                              return TransactionInProgress(
+                                transType: 'comfirmIdty',
+                                fromAddress: wallet.address,
+                                toAddress: wallet.address,
+                              );
                             }),
                           );
                         }
diff --git a/lib/screens/myWallets/import_g1_v1.dart b/lib/screens/myWallets/import_g1_v1.dart
index a9fbc21d..3833be9f 100644
--- a/lib/screens/myWallets/import_g1_v1.dart
+++ b/lib/screens/myWallets/import_g1_v1.dart
@@ -60,14 +60,14 @@ class ImportG1v1 extends StatelessWidget {
                 builder: (BuildContext context, AsyncSnapshot<List> 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;
+                  final Map balance = status.data?[0] ?? 0;
+                  final String idtyStatus = status.data?[1];
+                  final String myIdtyStatus = status.data?[2];
+                  final bool hasConsumer = status.data?[3] ?? false;
 
                   // log.d('hasconsumer: $hasConsumer');
 
-                  if (balance != 0 && !hasConsumer) {
+                  if (balance['transferableBalance'] != 0 && !hasConsumer) {
                     canValidate = true;
                     validationStatus = '';
                   } else {
@@ -87,9 +87,6 @@ class ImportG1v1 extends StatelessWidget {
                     validationStatus = '';
                   }
 
-                  log.d(
-                      'tatatata: ${sub.g1V1NewAddress}, ${selectedWallet.address!}, $balance, $idtyStatus, $myIdtyStatus');
-
                   return Column(children: <Widget>[
                     const SizedBox(height: 20),
                     TextFormField(
@@ -234,13 +231,17 @@ class ImportG1v1 extends StatelessWidget {
                                     sub.csSalt.text,
                                     sub.csPassword.text,
                                     selectedWallet.address!,
-                                    destPassword: pin ?? myWalletProvider.pinCode,
+                                    destPassword:
+                                        pin ?? myWalletProvider.pinCode,
                                     balance: balance,
                                     idtyStatus: idtyStatus);
                                 Navigator.push(
                                   context,
                                   MaterialPageRoute(builder: (context) {
-                                    return const TransactionInProgress();
+                                    return TransactionInProgress(
+                                        transType: 'identityMigration',
+                                        fromAddress: sub.g1V1NewAddress,
+                                        toAddress: selectedWallet.address);
                                   }),
                                 );
                                 resetScreen(context);
diff --git a/lib/screens/myWallets/manage_membership.dart b/lib/screens/myWallets/manage_membership.dart
index 5f4759fd..4a05ec05 100644
--- a/lib/screens/myWallets/manage_membership.dart
+++ b/lib/screens/myWallets/manage_membership.dart
@@ -1,6 +1,8 @@
+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/screens/myWallets/migrate_identity.dart';
 // import 'package:gecko/models/wallet_data.dart';
 // import 'package:gecko/providers/my_wallets.dart';
 // import 'package:gecko/providers/substrate_sdk.dart';
@@ -22,19 +24,44 @@ class ManageMembership extends StatelessWidget {
         backgroundColor: backgroundColor,
         appBar: AppBar(
             toolbarHeight: 60 * ratio,
-            title: const SizedBox(
+            title: SizedBox(
               height: 22,
-              child: Text('manageMembership'),
+              child: const Text('manageMembership').tr(),
             )),
         body: SafeArea(
           child: Column(children: <Widget>[
             const SizedBox(height: 20),
-            revokeMyIdentity(context),
+            migrateIdentity(context),
+            const SizedBox(height: 10),
+            revokeMyIdentity(context)
             // const SizedBox(height: 20),
           ]),
         ));
   }
 
+  Widget migrateIdentity(BuildContext context) {
+    return InkWell(
+      key: const Key('migrateIdentity'),
+      onTap: () async {
+        Navigator.push(
+          context,
+          MaterialPageRoute(builder: (context) {
+            return const MigrateIdentityScreen();
+          }),
+        );
+      },
+      child: SizedBox(
+        height: 60,
+        child: Row(children: const <Widget>[
+          SizedBox(width: 16),
+          Icon(Icons.change_circle_outlined, size: 35),
+          SizedBox(width: 11.5),
+          Text('Migrer mon identité', style: TextStyle(fontSize: 20)),
+        ]),
+      ),
+    );
+  }
+
   Widget revokeMyIdentity(BuildContext context) {
     return InkWell(
       key: const Key('revokeIdty'),
@@ -79,14 +106,15 @@ class ManageMembership extends StatelessWidget {
         // }
       },
       child: SizedBox(
-        height: 40,
-        child: Row(children: const <Widget>[
-          SizedBox(width: 32),
-          // Image.asset(
-          //   'assets/medal.png',
-          //   height: 45,
-          // ),
-          Text('Révoquer mon adhésion', style: TextStyle(fontSize: 20)),
+        height: 60,
+        child: Row(children: <Widget>[
+          const SizedBox(width: 20),
+          Image.asset(
+            'assets/skull_Icon.png',
+            height: 30,
+          ),
+          const SizedBox(width: 16),
+          const Text('Révoquer mon adhésion', style: TextStyle(fontSize: 20)),
         ]),
       ),
     );
diff --git a/lib/screens/myWallets/migrate_identity.dart b/lib/screens/myWallets/migrate_identity.dart
new file mode 100644
index 00000000..2bb06242
--- /dev/null
+++ b/lib/screens/myWallets/migrate_identity.dart
@@ -0,0 +1,251 @@
+// ignore_for_file: use_build_context_synchronously
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_markdown/flutter_markdown.dart';
+import 'package:gecko/globals.dart';
+import 'package:flutter/material.dart';
+import 'package:gecko/models/wallet_data.dart';
+import 'package:gecko/providers/duniter_indexer.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/myWallets/unlocking_wallet.dart';
+import 'package:gecko/screens/transaction_in_progress.dart';
+import 'package:provider/provider.dart';
+
+class MigrateIdentityScreen extends StatelessWidget {
+  const MigrateIdentityScreen({Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
+    // HomeProvider _homeProvider = Provider.of<HomeProvider>(context);
+    WalletOptionsProvider walletOptions =
+        Provider.of<WalletOptionsProvider>(context, listen: false);
+    MyWalletsProvider myWalletProvider =
+        Provider.of<MyWalletsProvider>(context, listen: false);
+    DuniterIndexer duniterIndexer =
+        Provider.of<DuniterIndexer>(context, listen: false);
+
+    final fromAddress = walletOptions.address.text;
+    final defaultWallet = myWalletProvider.getDefaultWallet();
+    final walletsList = myWalletProvider.listWallets.toList();
+    late WalletData selectedWallet;
+
+    if (fromAddress == defaultWallet.address) {
+      selectedWallet =
+          walletsList[fromAddress == walletsList[0].address ? 1 : 0];
+    } else {
+      selectedWallet = defaultWallet;
+    }
+    bool canValidate = false;
+    String validationStatus = '';
+
+    final mdStyle = MarkdownStyleSheet(
+      p: const TextStyle(fontSize: 18, color: Colors.black, letterSpacing: 0.3),
+      textAlign: WrapAlignment.center,
+    );
+
+    if (walletsList.length < 2) {
+      return Column(
+        children: [
+          const SizedBox(height: 80),
+          Row(
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: const [
+              Text(
+                'Vous devez avoir au moins 2 portefeuilles\npour effecter cette opération',
+                style: TextStyle(fontSize: 20),
+              )
+            ],
+          )
+        ],
+      );
+    }
+
+    return Scaffold(
+      backgroundColor: backgroundColor,
+      appBar: AppBar(
+          toolbarHeight: 60 * ratio,
+          title: SizedBox(
+            height: 22,
+            child: Text('importOldAccount'.tr()),
+          )),
+      body: SafeArea(
+        child: Consumer<SubstrateSdk>(builder: (context, sub, _) {
+          return FutureBuilder(
+              future: sub.getBalanceAndIdtyStatus(
+                  fromAddress, selectedWallet.address!),
+              builder: (BuildContext context, AsyncSnapshot<List> status) {
+                if (status.data == null) {
+                  return Column(children: [
+                    const SizedBox(height: 80),
+                    Row(mainAxisAlignment: MainAxisAlignment.center, children: [
+                      SizedBox(
+                        height: 35,
+                        width: 35,
+                        child: CircularProgressIndicator(
+                          color: orangeC,
+                          strokeWidth: 4,
+                        ),
+                      ),
+                    ]),
+                  ]);
+                }
+
+                // log.d('statusData: ${status.data}');
+
+                final Map balance = status.data?[0] ?? {};
+                final String idtyStatus = status.data?[1];
+                final String myIdtyStatus = status.data?[2];
+                final bool hasConsumer = status.data?[3] ?? false;
+
+                // log.d('hasconsumer: $hasConsumer');
+
+                if (balance['transferableBalance'] != 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();
+                }
+
+                log.d(
+                    'tatatata: ${sub.g1V1NewAddress}, ${selectedWallet.address!}, $balance, $idtyStatus, $myIdtyStatus');
+
+                final walletsList = myWalletProvider.listWallets.toList();
+
+                walletsList
+                    .removeWhere((element) => element.address == fromAddress);
+                // walletsList.add(WalletData(address: 'custom', name: 'custom'));
+
+                return Column(children: <Widget>[
+                  Row(children: const []),
+                  const SizedBox(height: 20),
+
+                  SizedBox(
+                    width: 350,
+                    child: MarkdownBody(
+                        data: 'areYouSureMigrateIdentity'.tr(args: [
+                          duniterIndexer.walletNameIndexer[fromAddress] ??
+                              '???',
+                          '${balance['transferableBalance']} $currencyName'
+                        ]),
+                        styleSheet: mdStyle),
+                  ),
+                  // Text(
+                  //   'areYouSureMigrateIdentity'.tr(args: [
+                  //     duniterIndexer
+                  //         .walletNameIndexer[fromAddress]!,
+                  //     '$balance $currencyName'
+                  //   ]),
+                  //   textAlign: TextAlign.center,
+                  // ),
+                  const SizedBox(height: 20),
+                  Text(
+                    sub.g1V1NewAddress,
+                    style: const TextStyle(
+                        fontSize: 14.0,
+                        color: Colors.black,
+                        fontWeight: FontWeight.bold,
+                        fontFamily: 'Monospace'),
+                  ),
+                  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: walletsList.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');
+                              WalletData? defaultWallet =
+                                  myWalletProvider.getDefaultWallet();
+
+                              String? pin;
+                              if (myWalletProvider.pinCode == '') {
+                                pin = await Navigator.push(
+                                  context,
+                                  MaterialPageRoute(
+                                    builder: (homeContext) {
+                                      return UnlockingWallet(
+                                          wallet: defaultWallet);
+                                    },
+                                  ),
+                                );
+                              }
+
+                              sub.migrateIdentity(
+                                  fromAddress: fromAddress,
+                                  destAddress: selectedWallet.address!,
+                                  fromPassword: pin ?? myWalletProvider.pinCode,
+                                  destPassword: pin ?? myWalletProvider.pinCode,
+                                  withBalance: true,
+                                  fromBalance: balance);
+                              Navigator.push(
+                                context,
+                                MaterialPageRoute(builder: (context) {
+                                  return TransactionInProgress(
+                                      transType: 'identityMigration',
+                                      fromAddress: fromAddress,
+                                      toAddress: selectedWallet.address);
+                                }),
+                              );
+                            }
+                          : null,
+                      child: Text(
+                        'migrateIdentity'.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]),
+                  )
+                ]);
+              });
+        }),
+      ),
+    );
+  }
+}
diff --git a/lib/screens/transaction_in_progress.dart b/lib/screens/transaction_in_progress.dart
index 6ab820ba..dafd381a 100644
--- a/lib/screens/transaction_in_progress.dart
+++ b/lib/screens/transaction_in_progress.dart
@@ -11,9 +11,12 @@ import 'package:provider/provider.dart';
 
 // ignore: must_be_immutable
 class TransactionInProgress extends StatelessWidget {
-  const TransactionInProgress({Key? key, this.transType = 'pay'})
+  const TransactionInProgress(
+      {Key? key, this.transType = 'pay', this.fromAddress, this.toAddress})
       : super(key: key);
   final String transType;
+  final String? fromAddress;
+  final String? toAddress;
 
   @override
   Widget build(BuildContext context) {
@@ -32,8 +35,8 @@ class TransactionInProgress extends StatelessWidget {
 
     log.d(walletViewProvider.address!);
 
-    final from = myWalletProvider.getDefaultWallet().name!;
-    final to = getShortPubkey(walletViewProvider.address!);
+    final from = fromAddress ?? myWalletProvider.getDefaultWallet().name!;
+    final to = toAddress ?? getShortPubkey(walletViewProvider.address!);
     final amount = walletViewProvider.payAmount.text;
     String actionName = '';
 
@@ -58,6 +61,11 @@ class TransactionInProgress extends StatelessWidget {
           actionName = "revokeAdhesion".tr();
         }
         break;
+      case 'identityMigration':
+        {
+          actionName = "identityMigration".tr();
+        }
+        break;
       default:
         {
           actionName = 'strangeTransaction'.tr();
@@ -148,7 +156,9 @@ class TransactionInProgress extends StatelessWidget {
         onWillPop: () {
           sub.transactionStatus = '';
           Navigator.pop(context);
-          if (transType == 'pay') Navigator.pop(context);
+          if (transType == 'pay' || transType == 'identityMigration') {
+            Navigator.pop(context);
+          }
           return Future<bool>.value(true);
         },
         child: Scaffold(
@@ -261,7 +271,10 @@ class TransactionInProgress extends StatelessWidget {
                           onPressed: () {
                             Navigator.pop(context);
                             sub.transactionStatus = '';
-                            if (transType == 'pay') Navigator.pop(context);
+                            if (transType == 'pay' ||
+                                transType == 'identityMigration') {
+                              Navigator.pop(context);
+                            }
                           },
                           child: Text(
                             'close'.tr(),
-- 
GitLab