diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart index 3b3e9c636..e9f6ac4e7 100644 --- a/cw_bitcoin/lib/bitcoin_wallet.dart +++ b/cw_bitcoin/lib/bitcoin_wallet.dart @@ -109,4 +109,4 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { networkParam: snp.network, ); } -} +} \ No newline at end of file diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index 873fe2977..9c786356c 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -23,6 +23,7 @@ import 'package:cw_bitcoin/litecoin_network.dart'; import 'package:cw_bitcoin/pending_bitcoin_transaction.dart'; import 'package:cw_bitcoin/script_hash.dart'; import 'package:cw_bitcoin/utils.dart'; +import 'package:cw_core/balance.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/node.dart'; import 'package:cw_core/pathForWallet.dart'; @@ -45,9 +46,8 @@ part 'electrum_wallet.g.dart'; class ElectrumWallet = ElectrumWalletBase with _$ElectrumWallet; -abstract class ElectrumWalletBase - extends WalletBase - with Store { +abstract class ElectrumWalletBase + extends WalletBase with Store { ElectrumWalletBase( {required String password, required WalletInfo walletInfo, @@ -55,9 +55,14 @@ abstract class ElectrumWalletBase required this.networkType, required this.mnemonic, required Uint8List seedBytes, + required T Function({ + required int confirmed, + required int unconfirmed, + required int frozen, + }) this.balanceFactory, List? initialAddresses, ElectrumClient? electrumClient, - ElectrumBalance? initialBalance, + T? initialBalance, CryptoCurrency? currency}) : hd = currency == CryptoCurrency.bch ? bitcoinCashHDWallet(seedBytes) @@ -69,12 +74,8 @@ abstract class ElectrumWalletBase isEnabledAutoGenerateSubaddress = true, unspentCoins = [], _scripthashesUpdateSubject = {}, - balance = ObservableMap.of(currency != null - ? { - currency: - initialBalance ?? const ElectrumBalance(confirmed: 0, unconfirmed: 0, frozen: 0) - } - : {}), + balance = ObservableMap.of( + currency != null ? {currency: initialBalance ?? balanceFactory(confirmed: 0, unconfirmed: 0, frozen: 0)} : {}), this.unspentCoinsInfo = unspentCoinsInfo, this.network = networkType == bitcoin.bitcoin ? BitcoinNetwork.mainnet @@ -96,6 +97,11 @@ abstract class ElectrumWalletBase final bitcoin.HDWallet hd; final String mnemonic; + final T Function({ + required int confirmed, + required int unconfirmed, + required int frozen, + }) balanceFactory; @override @observable @@ -109,7 +115,7 @@ abstract class ElectrumWalletBase @override @observable - late ObservableMap balance; + late ObservableMap balance; @override @observable @@ -285,7 +291,7 @@ abstract class ElectrumWalletBase final totalAmount = amount + fee; - if (totalAmount > balance[currency]!.confirmed) { + if (totalAmount > (balance[currency]!.confirmed as int)) { throw BitcoinTransactionWrongBalanceException(currency); } @@ -788,7 +794,7 @@ abstract class ElectrumWalletBase }); } - Future _fetchBalances() async { + Future _fetchBalances() async { final addresses = walletAddresses.allAddresses.toList(); final balanceFutures = >>[]; for (var i = 0; i < addresses.length; i++) { @@ -828,8 +834,15 @@ abstract class ElectrumWalletBase } } - return ElectrumBalance( - confirmed: totalConfirmed, unconfirmed: totalUnconfirmed, frozen: totalFrozen); + // return balanceFactory() + // ..confirmed = totalConfirmed + // ..unconfirmed = totalUnconfirmed + // ..frozen = totalFrozen; + return balanceFactory( + confirmed: totalConfirmed, + unconfirmed: totalUnconfirmed, + frozen: totalFrozen, + ); } Future updateBalance() async { diff --git a/cw_lightning/lib/lightning_balance.dart b/cw_lightning/lib/lightning_balance.dart index 23875e813..c07d5e651 100644 --- a/cw_lightning/lib/lightning_balance.dart +++ b/cw_lightning/lib/lightning_balance.dart @@ -1,10 +1,15 @@ import 'dart:convert'; import 'package:cw_bitcoin/bitcoin_amount_format.dart'; +import 'package:cw_bitcoin/electrum_balance.dart'; import 'package:cw_core/balance.dart'; -class LightningBalance extends Balance { +class LightningBalance extends ElectrumBalance { const LightningBalance({required this.confirmed, required this.unconfirmed, required this.frozen}) - : super(confirmed, unconfirmed); + : super( + confirmed: confirmed, + unconfirmed: unconfirmed, + frozen: frozen, + ); static LightningBalance? fromJSON(String? jsonSource) { if (jsonSource == null) { diff --git a/cw_lightning/lib/lightning_wallet.dart b/cw_lightning/lib/lightning_wallet.dart index cfaf4c5be..88217c136 100644 --- a/cw_lightning/lib/lightning_wallet.dart +++ b/cw_lightning/lib/lightning_wallet.dart @@ -1,12 +1,15 @@ import 'dart:convert'; import 'dart:io'; +import 'package:bitbox/bitbox.dart'; import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:breez_sdk/breez_sdk.dart'; import 'package:breez_sdk/bridge_generated.dart'; import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; import 'package:cw_bitcoin/bitcoin_wallet_keys.dart'; import 'package:cw_bitcoin/electrum.dart'; +import 'package:cw_bitcoin/electrum_balance.dart'; +import 'package:cw_bitcoin/electrum_transaction_info.dart'; import 'package:cw_bitcoin/electrum_wallet_addresses.dart'; import 'package:cw_bitcoin/electrum_wallet_snapshot.dart'; import 'package:cw_bitcoin/litecoin_network.dart'; @@ -33,33 +36,27 @@ import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart'; import 'package:path_provider/path_provider.dart'; import 'package:cw_lightning/.secrets.g.dart' as secrets; import 'package:cw_core/wallet_base.dart'; +import 'package:cw_bitcoin/electrum_wallet.dart'; part 'lightning_wallet.g.dart'; class LightningWallet = LightningWalletBase with _$LightningWallet; -abstract class LightningWalletBase - extends WalletBase - with Store { - final bitcoin.HDWallet hd; - final String mnemonic; - final String _password; +ElectrumBalance myBalanceFactory( + {required int confirmed, required int unconfirmed, required int frozen}) { + return ElectrumBalance( + confirmed: confirmed, + unconfirmed: unconfirmed, + frozen: frozen, + ); +} + +abstract class LightningWalletBase extends ElectrumWalletBase with Store { bool _isTransactionUpdating; - late ElectrumClient electrumClient; - @override - @observable - late ObservableMap balance; - - @override - late ElectrumWalletAddresses walletAddresses; - - bitcoin.NetworkType networkType = bitcoin.bitcoin; - late BasedUtxoNetwork network; - - @override - BitcoinWalletKeys get keys => - BitcoinWalletKeys(wif: hd.wif!, privateKey: hd.privKey!, publicKey: hd.pubKey!); + // @override + // @observable + // ObservableMap lnbalance; @override @observable @@ -72,45 +69,43 @@ abstract class LightningWalletBase required Box unspentCoinsInfo, required Uint8List seedBytes, String? addressPageType, - ElectrumClient? electrumClient, - BasedUtxoNetwork? networkParam, List? initialAddresses, LightningBalance? initialBalance, Map? initialRegularAddressIndex, Map? initialChangeAddressIndex, - }) : hd = bitcoin.HDWallet.fromSeed(seedBytes, network: bitcoin.bitcoin).derivePath("m/0'/0"), + }) : _isTransactionUpdating = false, syncStatus = NotConnectedSyncStatus(), - mnemonic = mnemonic, - _password = password, - _isTransactionUpdating = false, - balance = ObservableMap.of({ - CryptoCurrency.btcln: - initialBalance ?? const LightningBalance(confirmed: 0, unconfirmed: 0, frozen: 0) - }), - super(walletInfo) { - transactionHistory = LightningTransactionHistory(walletInfo: walletInfo, password: password); - - this.network = networkType == bitcoin.bitcoin - ? BitcoinNetwork.mainnet - : networkType == litecoinNetwork - ? LitecoinNetwork.mainnet - : BitcoinNetwork.testnet; - this.isTestnet = networkType == bitcoin.testnet; - + super( + mnemonic: mnemonic, + password: password, + walletInfo: walletInfo, + unspentCoinsInfo: unspentCoinsInfo, + networkType: bitcoin.bitcoin, + initialAddresses: initialAddresses, + initialBalance: initialBalance, + seedBytes: seedBytes, + currency: CryptoCurrency.btcln, + // balanceFactory: myBalanceFactory, + balanceFactory: ({required int confirmed, required int unconfirmed, required int frozen}) { + return LightningBalance( + confirmed: 0, + unconfirmed: 0, + frozen: 0, + ); + }, + ) { walletAddresses = BitcoinWalletAddresses( walletInfo, - electrumClient: electrumClient ?? ElectrumClient(), + electrumClient: electrumClient, initialAddresses: initialAddresses, initialRegularAddressIndex: initialRegularAddressIndex, initialChangeAddressIndex: initialChangeAddressIndex, mainHd: hd, sideHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/1"), - network: networkParam ?? network, + network: network, ); - this.electrumClient = electrumClient ?? ElectrumClient(); - - // initialize breeze: + // initialize breez: try { setupBreez(seedBytes); } catch (e) { @@ -122,25 +117,27 @@ abstract class LightningWalletBase }); } - static Future create({ - required String mnemonic, - required String password, - required WalletInfo walletInfo, - required Box unspentCoinsInfo, - BasedUtxoNetwork? network, - List? initialAddresses, - Map? initialRegularAddressIndex, - Map? initialChangeAddressIndex, - }) async { + static Future create( + {required String mnemonic, + required String password, + required WalletInfo walletInfo, + required Box unspentCoinsInfo, + String? addressPageType, + List? initialAddresses, + LightningBalance? initialBalance, + Map? initialRegularAddressIndex, + Map? initialChangeAddressIndex}) async { return LightningWallet( mnemonic: mnemonic, password: password, walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfo, initialAddresses: initialAddresses, - seedBytes: await mnemonicToSeedBytes(mnemonic), + initialBalance: initialBalance, + seedBytes: await Mnemonic.toSeed(mnemonic), initialRegularAddressIndex: initialRegularAddressIndex, initialChangeAddressIndex: initialChangeAddressIndex, + addressPageType: addressPageType, ); } @@ -150,20 +147,19 @@ abstract class LightningWalletBase required Box unspentCoinsInfo, required String password, }) async { - final snp = await ElectrumWalletSnapshot.load(name, walletInfo.type, password, - walletInfo.network != null ? BasedUtxoNetwork.fromName(walletInfo.network!) : null); - + final snp = await ElectrumWalletSnapshot.load( + name, walletInfo.type, password, BitcoinCashNetwork.mainnet); return LightningWallet( mnemonic: snp.mnemonic, password: password, walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfo, initialAddresses: snp.addresses, + initialBalance: snp.balance as LightningBalance?, seedBytes: await mnemonicToSeedBytes(snp.mnemonic), initialRegularAddressIndex: snp.regularAddressIndex, initialChangeAddressIndex: snp.changeAddressIndex, addressPageType: snp.addressPageType, - networkParam: snp.network, ); } @@ -224,11 +220,6 @@ abstract class LightningWalletBase print("initialized breez: ${(await sdk.isInitialized())}"); } - @override - int calculateEstimatedFee(TransactionPriority priority, int? amount) { - throw UnimplementedError("calculateEstimatedFee"); - } - @action @override Future startSync() async { @@ -248,9 +239,6 @@ abstract class LightningWalletBase throw UnimplementedError("changePassword"); } - @override - void close() {} - @action @override Future connectToNode({required Node node}) async { @@ -287,15 +275,15 @@ abstract class LightningWalletBase } } - Map convertToTxInfo(List payments) { - Map transactions = {}; + Map convertToTxInfo(List payments) { + Map transactions = {}; for (Payment tx in payments) { if (tx.paymentType == PaymentType.ClosedChannel) { continue; } bool isSend = tx.paymentType == PaymentType.Sent; - transactions[tx.id] = LightningTransactionInfo( + transactions[tx.id] = ElectrumTransactionInfo( WalletType.lightning, isPending: false, id: tx.id, @@ -303,13 +291,16 @@ abstract class LightningWalletBase fee: tx.feeMsat ~/ 1000, date: DateTime.fromMillisecondsSinceEpoch(tx.paymentTime * 1000), direction: isSend ? TransactionDirection.outgoing : TransactionDirection.incoming, + // N/A for lightning: + height: 0, + confirmations: 0, ); } return transactions; } @override - Future> fetchTransactions() async { + Future> fetchTransactions() async { final sdk = await BreezSDK(); final payments = await sdk.listPayments(req: ListPaymentsRequest()); @@ -341,13 +332,6 @@ abstract class LightningWalletBase 'network_type': network == BitcoinNetwork.testnet ? 'testnet' : 'mainnet', }); - @override - Future save() async { - final path = await makePath(); - await write(path: path, password: _password, data: toJSON()); - await transactionHistory.save(); - } - Future updateBalance() async { // balance is updated automatically } diff --git a/cw_lightning/lib/lightning_wallet_service.dart b/cw_lightning/lib/lightning_wallet_service.dart index 59b2b04c7..a458f9efa 100644 --- a/cw_lightning/lib/lightning_wallet_service.dart +++ b/cw_lightning/lib/lightning_wallet_service.dart @@ -26,10 +26,11 @@ class LightningWalletService extends WalletService create(BitcoinNewWalletCredentials credentials, {bool? isTestnet}) async { final wallet = await LightningWalletBase.create( - mnemonic: await generateMnemonic(), - password: credentials.password!, - walletInfo: credentials.walletInfo!, - unspentCoinsInfo: unspentCoinsInfoSource); + mnemonic: await generateMnemonic(), + password: credentials.password!, + walletInfo: credentials.walletInfo!, + unspentCoinsInfo: unspentCoinsInfoSource, + ); await wallet.save(); await wallet.init(); return wallet; @@ -45,20 +46,22 @@ class LightningWalletService extends WalletService info.id == WalletBase.idFor(name, getType()))!; try { final wallet = await LightningWalletBase.open( - password: password, - name: name, - walletInfo: walletInfo, - unspentCoinsInfo: unspentCoinsInfoSource); + password: password, + name: name, + walletInfo: walletInfo, + unspentCoinsInfo: unspentCoinsInfoSource, + ); await wallet.init(); saveBackup(name); return wallet; } catch (_) { await restoreWalletFilesFromBackup(name); final wallet = await LightningWalletBase.open( - password: password, - name: name, - walletInfo: walletInfo, - unspentCoinsInfo: unspentCoinsInfoSource); + password: password, + name: name, + walletInfo: walletInfo, + unspentCoinsInfo: unspentCoinsInfoSource, + ); await wallet.init(); return wallet; } @@ -93,7 +96,8 @@ class LightningWalletService extends WalletService restoreFromKeys(BitcoinRestoreWalletFromWIFCredentials credentials, {bool? isTestnet}) async => + Future restoreFromKeys(BitcoinRestoreWalletFromWIFCredentials credentials, + {bool? isTestnet}) async => throw UnimplementedError(); @override @@ -111,7 +115,6 @@ class LightningWalletService extends WalletService { this.fromBottomEdge = 25, this.moneroIcon = Image.asset('assets/images/monero_menu.png'), this.bitcoinIcon = Image.asset('assets/images/bitcoin_menu.png'), - this.lightningIcon = Image.asset('assets/images/bitcoin_menu.png'), + this.lightningIcon = Image.asset('assets/images/lightning_logo.png'), this.litecoinIcon = Image.asset('assets/images/litecoin_menu.png'), this.havenIcon = Image.asset('assets/images/haven_menu.png'), this.ethereumIcon = Image.asset('assets/images/eth_icon.png'), @@ -100,7 +100,7 @@ class MenuWidgetState extends State { color: Theme.of(context).extension()!.iconColor); bitcoinIcon = Image.asset('assets/images/bitcoin_menu.png', color: Theme.of(context).extension()!.iconColor); - lightningIcon = Image.asset('assets/images/bitcoin_menu.png', + lightningIcon = Image.asset('assets/images/lightning_logo.png', color: Theme.of(context).extension()!.iconColor); return Row( diff --git a/lib/src/screens/receive/lightning_receive_page.dart b/lib/src/screens/receive/lightning_receive_page.dart index 5b2e4e5b2..af64753c8 100644 --- a/lib/src/screens/receive/lightning_receive_page.dart +++ b/lib/src/screens/receive/lightning_receive_page.dart @@ -208,9 +208,9 @@ class LightningReceiveOnchainPage extends BasePage { return Expanded( child: Container(child: Center(child: CircularProgressIndicator()))); } - int min = (snapshot.data as List)[1]; - int max = (snapshot.data as List)[2]; - int fee = (snapshot.data as List)[3]; + int min = int.parse((snapshot.data as List)[1]); + int max = int.parse((snapshot.data as List)[2]); + int fee = int.parse((snapshot.data as List)[3]); return Expanded( child: Text( S.of(context).lightning_receive_limits( diff --git a/lib/src/screens/receive/widgets/anonpay_currency_input_field.dart b/lib/src/screens/receive/widgets/anonpay_currency_input_field.dart index 689913a82..f12156ed7 100644 --- a/lib/src/screens/receive/widgets/anonpay_currency_input_field.dart +++ b/lib/src/screens/receive/widgets/anonpay_currency_input_field.dart @@ -23,7 +23,7 @@ class AnonpayCurrencyInputField extends StatelessWidget { final String maxAmount; @override Widget build(BuildContext context) { - bool hasDecimals = selectedCurrency.name != "sats"; + bool hasDecimals = selectedCurrency.name.toLowerCase() != "sats"; final arrowBottomPurple = Image.asset( 'assets/images/arrow_bottom_purple_icon.png', color: Colors.white, diff --git a/lib/view_model/lightning_invoice_page_view_model.dart b/lib/view_model/lightning_invoice_page_view_model.dart index dad29bd61..29cf5e516 100644 --- a/lib/view_model/lightning_invoice_page_view_model.dart +++ b/lib/view_model/lightning_invoice_page_view_model.dart @@ -95,7 +95,7 @@ abstract class LightningInvoicePageViewModelBase with Store { try { String bolt11 = - await lightningViewModel.createInvoice(amount: amount, description: description); + await lightningViewModel.createInvoice(amountSats: amount, description: description); state = ExecutedSuccessfullyState(payload: bolt11); } catch (e) { state = FailureState(e.toString()); diff --git a/lib/view_model/lightning_view_model.dart b/lib/view_model/lightning_view_model.dart index beffb1468..59a90b7da 100644 --- a/lib/view_model/lightning_view_model.dart +++ b/lib/view_model/lightning_view_model.dart @@ -27,10 +27,10 @@ abstract class LightningViewModelBase with Store { ]; } - Future createInvoice({required String amount, String? description}) async { + Future createInvoice({required String amountSats, String? description}) async { final sdk = await BreezSDK(); final req = ReceivePaymentRequest( - amountMsat: (double.parse(amount) * 1000).round(), + amountMsat: (double.parse(amountSats) * 1000).round(), description: description ?? '', ); final res = await sdk.receivePayment(req: req); diff --git a/tool/generate_secrets_config.dart b/tool/generate_secrets_config.dart index 0dc040a59..c1cbe9506 100644 --- a/tool/generate_secrets_config.dart +++ b/tool/generate_secrets_config.dart @@ -42,6 +42,7 @@ Future generateSecretsConfig(List args) async { } } + // base: SecretKey.base.forEach((sec) { if (secrets[sec.name] != null) { return; @@ -49,12 +50,11 @@ Future generateSecretsConfig(List args) async { secrets[sec.name] = sec.generate(); }); - var secretsJson = JsonEncoder.withIndent(' ').convert(secrets); await configFile.writeAsString(secretsJson); - secrets.clear(); + // evm: SecretKey.evmChainsSecrets.forEach((sec) { if (secrets[sec.name] != null) { return; @@ -64,8 +64,9 @@ Future generateSecretsConfig(List args) async { }); secretsJson = JsonEncoder.withIndent(' ').convert(secrets); await evmChainsConfigFile.writeAsString(secretsJson); - secrets.clear(); + + // btc / lightning: SecretKey.bitcoinSecrets.forEach((sec) { if (secrets[sec.name] != null) { return; @@ -74,7 +75,9 @@ Future generateSecretsConfig(List args) async { }); secretsJson = JsonEncoder.withIndent(' ').convert(secrets); await bitcoinConfigFile.writeAsString(secretsJson); + secrets.clear(); + // solana: SecretKey.solanaSecrets.forEach((sec) { if (secrets[sec.name] != null) { return; @@ -84,4 +87,5 @@ Future generateSecretsConfig(List args) async { }); secretsJson = JsonEncoder.withIndent(' ').convert(secrets); await solanaConfigFile.writeAsString(secretsJson); + secrets.clear(); }