123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- import 'dart:async';
- import 'dart:convert';
- import 'dart:math';
- import 'package:bip39/bip39.dart' as bip39;
- import 'package:ethers/signers/wallet.dart' as ethers;
- import 'package:polkawallet_sdk/api/types/addressIconData.dart';
- import 'package:polkawallet_sdk/service/index.dart';
- import 'package:polkawallet_sdk/storage/keyringEVM.dart';
- import 'package:polkawallet_sdk/storage/types/ethWalletData.dart';
- import 'package:polkawallet_sdk/storage/types/keyPairData.dart';
- import 'package:web3dart/web3dart.dart';
- enum EVMKeyType { mnemonic, privateKey, keystore }
- const crypt_n = 1 << 14;
- /// KeyringEVM API manages EVM keyPairs
- class ApiEthers {
- ApiEthers(this.service);
- final SubstrateService? service;
- /// Generate a set of new mnemonic.
- Future<AddressIconDataWithMnemonic> generateMnemonic(
- {String derivePath = '', String key = ''}) async {
- final mnemonic = bip39.generateMnemonic();
- final wallet = ethers.Wallet.fromMnemonic(mnemonic);
- return AddressIconDataWithMnemonic.fromJson({
- 'mnemonic': mnemonic,
- 'address': wallet.address,
- 'svg': 'xxx',
- });
- }
- /// get address and avatar from mnemonic.
- Future<AddressIconData> addressFromMnemonic(String mnemonic,
- {String derivePath = ''}) async {
- final wallet = ethers.Wallet.fromMnemonic(mnemonic);
- return AddressIconData.fromJson({'address': wallet.address, 'svg': 'xxx'});
- }
- /// get address and avatar from privateKey.
- Future<AddressIconData> addressFromRawSeed(String privateKey,
- {String derivePath = ''}) async {
- final wallet = ethers.Wallet.fromPrivateKey(privateKey);
- return AddressIconData.fromJson({'address': wallet.address, 'svg': 'xxx'});
- }
- /// check mnemonic valid.
- Future<bool> checkMnemonicValid(String mnemonic) async {
- return bip39.validateMnemonic(mnemonic);
- }
- /// Import account from mnemonic/rawSeed/keystore and we get a JSON object.
- /// param [cryptoType] can be `sr25519`(default) or `ed25519`.
- /// throw error if import failed.
- /// return null if keystore password check failed.
- Future<Map<String, dynamic>> importAccount({
- required EVMKeyType keyType,
- required String key,
- required String name,
- required String password,
- String derivePath = '',
- }) async {
- Wallet web3Wallet;
- switch (keyType) {
- case EVMKeyType.mnemonic:
- final wallet = ethers.Wallet.fromMnemonic(key);
- final credential = EthPrivateKey.fromHex(wallet.privateKey!);
- web3Wallet = Wallet.createNew(credential, password, Random.secure(),
- scryptN: crypt_n);
- break;
- case EVMKeyType.privateKey:
- final credential = EthPrivateKey.fromHex(key);
- web3Wallet = Wallet.createNew(credential, password, Random.secure(),
- scryptN: crypt_n);
- break;
- case EVMKeyType.keystore:
- web3Wallet = Wallet.fromJson(key, password);
- }
- final walletJson = jsonDecode(web3Wallet.toJson());
- final type = keyType.toString().split('.')[1];
- return {
- ...walletJson,
- 'address': web3Wallet.privateKey.address.hexEip55,
- 'name': name,
- type: key,
- };
- }
- /// Add account to local storage.
- Future<EthWalletData> addAccount(
- KeyringEVM keyring, {
- required EVMKeyType keyType,
- required Map<String, dynamic> acc,
- required String password,
- }) async {
- // save seed and remove it before add account
- final type = keyType.toString().split('.')[1];
- if (keyType == EVMKeyType.mnemonic || keyType == EVMKeyType.privateKey) {
- final String? seed = acc[type];
- if (seed != null && seed.isNotEmpty) {
- keyring.store
- .encryptSeedAndSave(acc['address'], acc[type], type, password);
- }
- }
- acc.remove(type);
- // save keystore to storage
- await keyring.store.addAccount(acc);
- await updateIconsMap(keyring, [acc['address']]);
- return EthWalletData.fromJson(acc);
- }
- /// Add a contact.
- Future<EthWalletData> addContact(KeyringEVM keyring, Map acc) async {
- // save keystore to storage
- await keyring.store.addContact(acc);
- await updateIconsMap(keyring, [acc['address']]);
- return keyring.contacts.firstWhere((e) => e.address == acc['address']);
- }
- /// This method query account icons and set icons to [KeyringEVM.store]
- /// so we can get icon of an account from [KeyringEVM] instance.
- Future<void> updateIconsMap(KeyringEVM keyring, [List? addresses]) async {
- // final List<String?> ls = [];
- // if (addresses != null) {
- // ls.addAll(List<String>.from(addresses));
- // } else {
- // ls.addAll(keyring.keyPairs.map((e) => e.address).toList());
- // ls.addAll(keyring.contacts.map((e) => e.address).toList());
- // }
- //
- // if (ls.length == 0) return;
- // // get icons from webView.
- // final res = await service!.getPubKeyIconsMap(ls);
- // // set new icons to Keyring instance.
- // if (res != null) {
- // final data = {};
- // res.forEach((e) {
- // data[e[0]] = e[1];
- // });
- // keyring.store.updateIconsMap(Map<String, String>.from(data));
- // }
- }
- /// Decrypt and get the backup of seed.
- Future<bool> checkEncryptedSeedExist(
- KeyringEVM keyring, EthWalletData acc, EVMKeyType keyType) async {
- return keyring.store.checkSeedExist(keyType, acc.address ?? '');
- }
- /// Decrypt and get the backup of seed.
- Future<SeedBackupData?> getDecryptedSeed(
- KeyringEVM keyring, String password) async {
- final Map? data =
- await keyring.store.getDecryptedSeed(keyring.current.address, password);
- if (data == null) {
- return null;
- }
- if (data['seed'] == null) {
- data['error'] = 'wrong password';
- }
- return SeedBackupData.fromJson(data as Map<String, dynamic>);
- }
- /// delete account from storage
- Future<void> deleteAccount(KeyringEVM keyring, EthWalletData account) async {
- await keyring.store.deleteAccount(account.address);
- }
- /// check password of account
- Future<bool> checkPassword(EthWalletData account, String pass) async {
- try {
- Wallet.fromJson(jsonEncode(account.toJson()), pass);
- return true;
- } catch (err) {
- print(err.toString());
- // ignore
- }
- return false;
- }
- /// change password of account
- Future<EthWalletData?> changePassword(
- KeyringEVM keyring, String passOld, passNew) async {
- final acc = keyring.current;
- // 1. check old password
- final res = await checkPassword(acc, passOld);
- if (!res) {
- return null;
- }
- final wallet = Wallet.fromJson(jsonEncode(acc.toJson()), passOld);
- final walletNew = Wallet.createNew(
- wallet.privateKey, passNew, Random.secure(),
- scryptN: crypt_n);
- final walletJson = jsonDecode(walletNew.toJson());
- final accNew = EthWalletData()
- ..address = acc.address
- ..name = acc.name
- ..memo = acc.memo
- ..observation = acc.observation
- ..id = walletJson['id']
- ..version = walletJson['version']
- ..crypto = walletJson['crypto'];
- // 2. then update encrypted seed in local storage.
- keyring.store.updateEncryptedSeed(acc.address, passOld, passNew);
- // 3. update keyPair data in storage
- keyring.store.updateAccount(accNew.toJson());
- return accNew;
- }
- /// change name of account
- Future<KeyPairData> changeName(KeyringEVM keyring, String name) async {
- final json = keyring.current.toJson();
- json['name'] = name;
- // update keyPair date in storage
- keyring.store.updateAccount(json);
- return KeyPairData.fromJson(json);
- }
- // /// Open a new webView for a DApp,
- // /// sign extrinsic or msg for the DApp.
- // Future<ExtensionSignResult?> signAsExtension(
- // String password, SignAsExtensionParam param) async {
- // final signature = await service!.signAsExtension(password, param.toJson());
- // if (signature == null) {
- // return null;
- // }
- // final ExtensionSignResult res = ExtensionSignResult();
- // res.id = param.id;
- // res.signature = signature['signature'];
- // return res;
- // }
- //
- // Future<VerifyResult?> signatureVerify(
- // String message, signature, address) async {
- // final res = await service!.signatureVerify(message, signature, address);
- // if (res == null) {
- // return null;
- // }
- // return VerifyResult.fromJson(
- // Map<String, dynamic>.of(res as Map<String, dynamic>));
- // }
- }
|