diff --git a/cw_ethereum/lib/ethereum_balance.dart b/cw_ethereum/lib/ethereum_balance.dart index 433b5bb10..2c8bf4043 100644 --- a/cw_ethereum/lib/ethereum_balance.dart +++ b/cw_ethereum/lib/ethereum_balance.dart @@ -4,7 +4,7 @@ import 'package:cw_core/balance.dart'; import 'package:web3dart/web3dart.dart'; class EthereumBalance extends Balance { - EthereumBalance(super.available, super.additional); + EthereumBalance({required int available, required int additional}) : super(available, additional); @override String get formattedAdditionalBalance { @@ -18,4 +18,17 @@ class EthereumBalance extends Balance { EtherAmount.fromUnitAndValue(EtherUnit.ether, available.toString()).getInEther.toString(); String toJSON() => json.encode({'available': available, 'additional': additional}); + + static EthereumBalance? fromJSON(String? jsonSource) { + if (jsonSource == null) { + return null; + } + + final decoded = json.decode(jsonSource) as Map; + + return EthereumBalance( + available: decoded['available'] as int? ?? 0, + additional: decoded['additional'] as int? ?? 0, + ); + } } diff --git a/cw_ethereum/lib/ethereum_wallet.dart b/cw_ethereum/lib/ethereum_wallet.dart index 57ff39e75..ada98bb8d 100644 --- a/cw_ethereum/lib/ethereum_wallet.dart +++ b/cw_ethereum/lib/ethereum_wallet.dart @@ -18,6 +18,9 @@ import 'package:cw_ethereum/ethereum_wallet_addresses.dart'; import 'package:cw_ethereum/file.dart'; import 'package:mobx/mobx.dart'; import 'package:web3dart/web3dart.dart'; +import 'package:ed25519_hd_key/ed25519_hd_key.dart'; +import 'package:bip39/bip39.dart' as bip39; +import 'package:hex/hex.dart'; part 'ethereum_wallet.g.dart'; @@ -28,25 +31,24 @@ abstract class EthereumWalletBase with Store { EthereumWalletBase({ required WalletInfo walletInfo, - required this.mnemonic, - required this.privateKey, + required String mnemonic, required String password, EthereumBalance? initialBalance, }) : syncStatus = NotConnectedSyncStatus(), _password = password, + _mnemonic = mnemonic, walletAddresses = EthereumWalletAddresses(walletInfo), balance = ObservableMap.of( - {CryptoCurrency.eth: initialBalance ?? EthereumBalance(0, 0)}), + {CryptoCurrency.eth: initialBalance ?? EthereumBalance(available: 0, additional: 0)}), super(walletInfo) { this.walletInfo = walletInfo; - transactionHistory = EthereumTransactionHistory(); - walletAddresses.address = EthPrivateKey.fromHex(privateKey).address.toString(); } - final String mnemonic; - final String privateKey; + final String _mnemonic; final String _password; + late final String privateKey; + late EthereumClient _client; EtherAmount? _gasPrice; @@ -61,6 +63,12 @@ abstract class EthereumWalletBase @observable late ObservableMap balance; + Future init() async { + privateKey = await getPrivateKey(_mnemonic, _password); + transactionHistory = EthereumTransactionHistory(); + walletAddresses.address = EthPrivateKey.fromHex(privateKey).address.toString(); + } + @override int calculateEstimatedFee(TransactionPriority priority, int? amount) { throw UnimplementedError("calculateEstimatedFee"); @@ -119,7 +127,7 @@ abstract class EthereumWalletBase } @override - String get seed => mnemonic; + String get seed => _mnemonic; @override Future startSync() async { @@ -150,11 +158,31 @@ abstract class EthereumWalletBase Future makePath() async => pathForWallet(name: walletInfo.name, type: walletInfo.type); String toJSON() => json.encode({ - 'mnemonic': mnemonic, + 'mnemonic': _mnemonic, 'balance': balance[currency]!.toJSON(), // TODO: save other attributes }); + static Future open({ + required String name, + required String password, + required WalletInfo walletInfo, + }) async { + final path = await pathForWallet(name: name, type: walletInfo.type); + final jsonSource = await read(path: path, password: password); + final data = json.decode(jsonSource) as Map; + final mnemonic = data['mnemonic'] as String; + final balance = EthereumBalance.fromJSON(data['balance'] as String) ?? + EthereumBalance(available: 0, additional: 0); + + return EthereumWallet( + walletInfo: walletInfo, + password: password, + mnemonic: mnemonic, + initialBalance: balance, + ); + } + Future _updateBalance() async { balance[currency] = await _fetchBalances(); await save(); @@ -163,6 +191,17 @@ abstract class EthereumWalletBase Future _fetchBalances() async { final balance = await _client.getBalance(privateKey); - return EthereumBalance(balance.getInEther.toInt(), balance.getInEther.toInt()); + return EthereumBalance( + available: balance.getInEther.toInt(), + additional: balance.getInEther.toInt(), + ); + } + + Future getPrivateKey(String mnemonic, String password) async { + final seed = bip39.mnemonicToSeedHex(mnemonic); + final master = await ED25519_HD_KEY.getMasterKeyFromSeed(HEX.decode(seed), + masterSecret: password); + final privateKey = HEX.encode(master.key); + return privateKey; } } diff --git a/cw_ethereum/lib/ethereum_wallet_service.dart b/cw_ethereum/lib/ethereum_wallet_service.dart index 605f992fb..12e7b34d7 100644 --- a/cw_ethereum/lib/ethereum_wallet_service.dart +++ b/cw_ethereum/lib/ethereum_wallet_service.dart @@ -10,10 +10,8 @@ import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:cw_ethereum/ethereum_wallet.dart'; import 'package:cw_ethereum/ethereum_wallet_creation_credentials.dart'; -import 'package:ed25519_hd_key/ed25519_hd_key.dart'; import 'package:hive/hive.dart'; import 'package:bip39/bip39.dart' as bip39; -import 'package:hex/hex.dart'; class EthereumWalletService extends WalletService { @@ -24,13 +22,13 @@ class EthereumWalletService extends WalletService create(EthereumNewWalletCredentials credentials) async { final mnemonic = bip39.generateMnemonic(); - final privateKey = await getPrivateKey(mnemonic, credentials.password!); final wallet = EthereumWallet( walletInfo: credentials.walletInfo!, mnemonic: mnemonic, - privateKey: privateKey, password: credentials.password!, ); + + await wallet.init(); await wallet.save(); return wallet; @@ -44,10 +42,19 @@ class EthereumWalletService extends WalletService, TransactionInfo>> openWallet( - String name, String password) { - // TODO: implement openWallet - throw UnimplementedError(); + Future openWallet(String name, String password) async { + final walletInfo = + walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(name, getType())); + final wallet = await EthereumWalletBase.open( + name: name, + password: password, + walletInfo: walletInfo, + ); + + await wallet.init(); + await wallet.save(); + + return wallet; } @override @@ -66,12 +73,4 @@ class EthereumWalletService extends WalletService getPrivateKey(String mnemonic, String password) async { - final seed = bip39.mnemonicToSeedHex(mnemonic); - final master = await ED25519_HD_KEY.getMasterKeyFromSeed(HEX.decode(seed), - masterSecret: password); - final privateKey = HEX.encode(master.key); - return privateKey; - } }