keyringEVM.dart 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. import 'dart:async';
  2. import 'package:flutter_aes_ecb_pkcs5/flutter_aes_ecb_pkcs5.dart';
  3. import 'package:get_storage/get_storage.dart';
  4. import 'package:polkawallet_sdk/ethers/apiEthers.dart';
  5. import 'package:polkawallet_sdk/storage/localStorage.dart';
  6. import 'package:polkawallet_sdk/storage/types/ethWalletData.dart';
  7. import 'package:polkawallet_sdk/utils/index.dart';
  8. /// A [KeyringEVM] instance maintains the local storage
  9. /// of EVM key-pairs for users.
  10. /// We need to pass the storage instance to [WalletSDK]'s
  11. /// keyringEVM api for account management.
  12. class KeyringEVM {
  13. late KeyringEVMPrivateStore store;
  14. EthWalletData get current {
  15. final list = allAccounts;
  16. if (list.length > 0) {
  17. final i = list.indexWhere((e) => e.address == store.currentAddress);
  18. return i >= 0 ? list[i] : list[0];
  19. }
  20. return EthWalletData();
  21. }
  22. void setCurrent(EthWalletData acc) {
  23. store.setCurrentAddress(acc.address);
  24. }
  25. List<EthWalletData> get keyPairs {
  26. return store.list.map((e) => EthWalletData.fromJson(e)).toList();
  27. }
  28. List<EthWalletData> get externals {
  29. return store.externals.map((e) => EthWalletData.fromJson(e)).toList();
  30. }
  31. List<EthWalletData> get contacts {
  32. return store.contacts.map((e) => EthWalletData.fromJson(e)).toList();
  33. }
  34. List<EthWalletData> get allAccounts {
  35. final res = keyPairs;
  36. res.addAll(externals);
  37. return res;
  38. }
  39. List<EthWalletData> get allWithContacts {
  40. final res = keyPairs;
  41. res.addAll(contacts);
  42. return res;
  43. }
  44. List<EthWalletData> get optionals {
  45. final res = allAccounts;
  46. res.removeWhere((e) => e.address == current.address);
  47. return res;
  48. }
  49. Future<void> init() async {
  50. store = KeyringEVMPrivateStore();
  51. await store.init();
  52. // The first call is 0, so I call it once
  53. print(
  54. "_keyringEVM.keyPairs.length===${this.keyPairs.length}====_keyringEVM.contacts.length${this.contacts.length}");
  55. }
  56. }
  57. class KeyringEVMPrivateStore {
  58. final KeyringEVMStorage _storage = KeyringEVMStorage();
  59. Map<String, String> _iconsMap = {};
  60. String? get currentAddress => _storage.currentAddress.val;
  61. void setCurrentAddress(String? address) {
  62. _storage.currentAddress.val = address;
  63. }
  64. List get list {
  65. return _formatAccount(_storage.keyPairs.val.toList());
  66. }
  67. List get externals {
  68. final ls = _storage.contacts.val.toList();
  69. ls.retainWhere((e) => e['observation'] ?? false);
  70. return _formatAccount(ls);
  71. }
  72. List get contacts {
  73. return _formatAccount(_storage.contacts.val.toList());
  74. }
  75. List _formatAccount(List ls) {
  76. ls.forEach((e) {
  77. e['icon'] = _iconsMap[e['address']];
  78. });
  79. return ls;
  80. }
  81. /// the [GetStorage] package needs to be initiated before use.
  82. Future<void> init() async {
  83. await GetStorage.init(sdk_storage_key);
  84. }
  85. void updateIconsMap(Map<String, String> data) {
  86. _iconsMap.addAll(data);
  87. }
  88. Future<void> addAccount(Map acc) async {
  89. final pairs = _storage.keyPairs.val.toList();
  90. // remove duplicated account and add a new one
  91. pairs.retainWhere((e) => e['address'] != acc['address']);
  92. pairs.add(acc);
  93. _storage.keyPairs.val = pairs;
  94. setCurrentAddress(acc['address']);
  95. }
  96. Future<void> addContact(Map acc) async {
  97. final ls = _storage.contacts.val.toList();
  98. ls.add(acc);
  99. _storage.contacts.val = ls;
  100. if (acc['observation'] ?? false) {
  101. setCurrentAddress(acc['address']);
  102. }
  103. }
  104. Future<void> updateAccount(Map acc, {bool isExternal: false}) async {
  105. if (isExternal) {
  106. updateContact(acc);
  107. } else {
  108. _updateKeyPair(acc);
  109. }
  110. }
  111. Future<void> _updateKeyPair(Map acc) async {
  112. final List pairs = _storage.keyPairs.val.toList();
  113. pairs.removeWhere((e) => e['address'] == acc['address']);
  114. pairs.add(acc);
  115. _storage.keyPairs.val = pairs;
  116. }
  117. Future<void> updateContact(Map acc) async {
  118. final ls = _storage.contacts.val.toList();
  119. ls.removeWhere((e) => e['address'] == acc['address']);
  120. ls.add(acc);
  121. _storage.contacts.val = ls;
  122. }
  123. Future<void> deleteAccount(String? address) async {
  124. _deleteKeyPair(address);
  125. final mnemonics = Map.of(_storage.encryptedMnemonics.val);
  126. mnemonics.remove(address);
  127. _storage.encryptedMnemonics.val = mnemonics;
  128. final privateKeys = Map.of(_storage.encryptedPrivateKeys.val);
  129. privateKeys.remove(address);
  130. _storage.encryptedPrivateKeys.val = privateKeys;
  131. }
  132. Future<void> _deleteKeyPair(String? address) async {
  133. final List pairs = _storage.keyPairs.val.toList();
  134. pairs.removeWhere((e) => e['address'] == address);
  135. _storage.keyPairs.val = pairs;
  136. if (pairs.length > 0) {
  137. setCurrentAddress(pairs[0]['address']);
  138. } else if (externals.length > 0) {
  139. setCurrentAddress(externals[0]['address']);
  140. } else {
  141. setCurrentAddress('');
  142. }
  143. }
  144. Future<void> deleteContact(String address) async {
  145. final ls = _storage.contacts.val.toList();
  146. ls.removeWhere((e) => e['address'] == address);
  147. _storage.contacts.val = ls;
  148. }
  149. Future<void> encryptSeedAndSave(
  150. String? address, seed, seedType, password) async {
  151. final String key = Encrypt.passwordToEncryptKey(password);
  152. final encrypted = await FlutterAesEcbPkcs5.encryptString(seed, key);
  153. if (seedType == EVMKeyType.mnemonic.toString().split('.')[1]) {
  154. final mnemonics = Map.from(_storage.encryptedMnemonics.val);
  155. mnemonics.addAll({address: encrypted});
  156. _storage.encryptedMnemonics.val = mnemonics;
  157. return;
  158. }
  159. if (seedType == EVMKeyType.privateKey.toString().split('.')[1]) {
  160. final seeds = Map.from(_storage.encryptedPrivateKeys.val);
  161. seeds.addAll({address: encrypted});
  162. _storage.encryptedPrivateKeys.val = seeds;
  163. }
  164. }
  165. Future<void> updateEncryptedSeed(String? address, passOld, passNew) async {
  166. final seed = await getDecryptedSeed(address, passOld);
  167. if (seed != null) {
  168. encryptSeedAndSave(address, seed['seed'], seed['type'], passNew);
  169. }
  170. }
  171. Future<Map<String, dynamic>?> getDecryptedSeed(
  172. String? address, password) async {
  173. final key = Encrypt.passwordToEncryptKey(password);
  174. final mnemonic = _storage.encryptedMnemonics.val[address];
  175. if (mnemonic != null) {
  176. final Map<String, dynamic> res = {
  177. 'type': EVMKeyType.mnemonic.toString().split('.')[1]
  178. };
  179. try {
  180. res['seed'] = await FlutterAesEcbPkcs5.decryptString(mnemonic, key);
  181. } catch (err) {
  182. print(err);
  183. }
  184. return res;
  185. }
  186. final privateKey = _storage.encryptedPrivateKeys.val[address];
  187. if (privateKey != null) {
  188. final Map<String, dynamic> res = {
  189. 'type': EVMKeyType.privateKey.toString().split('.')[1]
  190. };
  191. try {
  192. res['seed'] = await FlutterAesEcbPkcs5.decryptString(privateKey, key);
  193. } catch (err) {
  194. print(err);
  195. }
  196. return res;
  197. }
  198. return null;
  199. }
  200. Future<bool> checkSeedExist(EVMKeyType keyType, String address) async {
  201. switch (keyType) {
  202. case EVMKeyType.mnemonic:
  203. return _storage.encryptedMnemonics.val[address] != null;
  204. case EVMKeyType.privateKey:
  205. return _storage.encryptedPrivateKeys.val[address] != null;
  206. default:
  207. return false;
  208. }
  209. }
  210. }