diff --git a/cw_nano/lib/nano_transaction_credentials.dart b/cw_nano/lib/nano_transaction_credentials.dart new file mode 100644 index 000000000..6ede488a1 --- /dev/null +++ b/cw_nano/lib/nano_transaction_credentials.dart @@ -0,0 +1,7 @@ +import 'package:cw_core/output_info.dart'; + +class NanoTransactionCredentials { + NanoTransactionCredentials(this.outputs); + + final List outputs; +} diff --git a/cw_nano/lib/nano_wallet.dart b/cw_nano/lib/nano_wallet.dart index 943bdf035..ab8bb84f8 100644 --- a/cw_nano/lib/nano_wallet.dart +++ b/cw_nano/lib/nano_wallet.dart @@ -16,6 +16,7 @@ import 'package:cw_nano/nano_transaction_history.dart'; import 'package:cw_nano/nano_transaction_info.dart'; import 'package:cw_nano/nano_util.dart'; import 'package:cw_nano/nano_wallet_info.dart'; +import 'package:cw_nano/pending_nano_transaction.dart'; import 'package:mobx/mobx.dart'; import 'dart:async'; import 'package:cw_nano/nano_wallet_addresses.dart'; @@ -126,55 +127,19 @@ abstract class NanoWalletBase print(credentials); // throw UnimplementedError(); - // final _credentials = credentials as EthereumTransactionCredentials; - // final outputs = _credentials.outputs; - // final hasMultiDestination = outputs.length > 1; - // final _erc20Balance = balance[_credentials.currency]!; - // BigInt totalAmount = BigInt.zero; - // int exponent = - // _credentials.currency is Erc20Token ? (_credentials.currency as Erc20Token).decimal : 18; - // BigInt amountToEthereumMultiplier = BigInt.from(pow(10, exponent)); + return PendingNanoTransaction( + amount: BigInt.one, + fee: 0, + id: "test", + nanoClient: _client, + ); - // if (hasMultiDestination) { - // if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) { - // throw EthereumTransactionCreationException(_credentials.currency); - // } - - // final totalOriginalAmount = EthereumFormatter.parseEthereumAmountToDouble( - // outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0))); - // totalAmount = BigInt.from(totalOriginalAmount) * amountToEthereumMultiplier; - - // if (_erc20Balance.balance < totalAmount) { - // throw EthereumTransactionCreationException(_credentials.currency); - // } - // } else { - // final output = outputs.first; - // final BigInt allAmount = _erc20Balance.balance - BigInt.from(feeRate(_credentials.priority!)); - // final totalOriginalAmount = - // EthereumFormatter.parseEthereumAmountToDouble(output.formattedCryptoAmount ?? 0); - // totalAmount = output.sendAll - // ? allAmount - // : BigInt.from(totalOriginalAmount) * amountToEthereumMultiplier; - - // if (_erc20Balance.balance < totalAmount) { - // throw EthereumTransactionCreationException(_credentials.currency); - // } - // } - - // final pendingEthereumTransaction = await _client.signTransaction( - // privateKey: _privateKey, - // toAddress: _credentials.outputs.first.address, - // amount: totalAmount.toString(), - // gas: _priorityFees[_credentials.priority!.raw], - // priority: _credentials.priority!, - // currency: _credentials.currency, - // exponent: exponent, - // contractAddress: _credentials.currency is Erc20Token - // ? (_credentials.currency as Erc20Token).contractAddress - // : null, - // ); - - // return pendingEthereumTransaction; + // return PendingNanoTransaction(txb.build(), type, + // electrumClient: electrumClient, amount: amount, fee: fee) + // ..addListener((transaction) async { + // transactionHistory.addOne(transaction); + // await updateBalance(); + // }); } Future updateTransactions() async { diff --git a/cw_nano/lib/nano_wallet_service.dart b/cw_nano/lib/nano_wallet_service.dart index 0794dec12..fca76bc1c 100644 --- a/cw_nano/lib/nano_wallet_service.dart +++ b/cw_nano/lib/nano_wallet_service.dart @@ -25,13 +25,13 @@ class NanoRestoreWalletFromSeedCredentials extends WalletCredentials { NanoRestoreWalletFromSeedCredentials( {required String name, required this.mnemonic, - required this.derivationType, + this.derivationType, int height = 0, String? password}) : super(name: name, password: password, height: height); final String mnemonic; - final DerivationType derivationType; + final DerivationType? derivationType; } class NanoWalletLoadingException implements Exception { @@ -44,9 +44,11 @@ class NanoRestoreWalletFromKeysCredentials extends WalletCredentials { required String name, required String password, required this.seedKey, + this.derivationType, }) : super(name: name, password: password); final String seedKey; + final DerivationType? derivationType; } class NanoWalletService extends WalletService create(NanoNewWalletCredentials credentials) async { - print("nano_wallet_service create"); final mnemonic = bip39.generateMnemonic(); - final nanoWalletInfo = NanoWalletInfo( walletInfo: credentials.walletInfo!, derivationType: DerivationType.nano, @@ -140,7 +140,7 @@ class NanoWalletService extends WalletService standardBalance.currentBalance) { return DerivationType.bip39; @@ -156,10 +156,10 @@ class NanoWalletService extends WalletService restoreFromKeys(NanoRestoreWalletFromKeysCredentials credentials) async { throw UnimplementedError("restoreFromKeys"); - // TODO: mnemonic can't be derived from the seedKey in the nanostandard derivation + // TODO: mnemonic can't be derived from the seedKey in the nano standard derivation // which complicates things - // DerivationType derivationType = await compareDerivationMethods(seedKey: credentials.seedKey); + // DerivationType derivationType = credentials.derivationType ?? await compareDerivationMethods(seedKey: credentials.seedKey); // String? mnemonic; // final nanoWalletInfo = NanoWalletInfo( // walletInfo: credentials.walletInfo!, @@ -185,7 +185,8 @@ class NanoWalletService extends WalletService id; + + // @override + // String get hex => _tx.toHex(); + + @override + String get amountFormatted => + NanoUtil.getRawAsUsableString(amount.toString(), NanoUtil.rawPerNano); + + @override + String get feeFormatted => "0"; + + // final List _listeners; + + @override + Future commit() async { + // final result = + // await electrumClient.broadcastTransaction(transactionRaw: _tx.toHex()); + + // if (result.isEmpty) { + // throw BitcoinCommitTransactionException(); + // } + + // _listeners?.forEach((listener) => listener(transactionInfo())); + } + + // void addListener( + // void Function(ElectrumTransactionInfo transaction) listener) => + // _listeners.add(listener); + + // ElectrumTransactionInfo transactionInfo() => ElectrumTransactionInfo(type, + // id: id, + // height: 0, + // amount: amount, + // direction: TransactionDirection.outgoing, + // date: DateTime.now(), + // isPending: true, + // confirmations: 0, + // fee: fee); +} diff --git a/lib/nano/cw_nano.dart b/lib/nano/cw_nano.dart index f03ea262f..7ad6b12e4 100644 --- a/lib/nano/cw_nano.dart +++ b/lib/nano/cw_nano.dart @@ -39,9 +39,9 @@ class CWNano extends Nano { @override WalletCredentials createNanoRestoreWalletFromSeedCredentials({ required String name, - required String mnemonic, - required DerivationType derivationType, required String password, + required String mnemonic, + DerivationType? derivationType, }) => NanoRestoreWalletFromSeedCredentials( name: name, @@ -61,4 +61,22 @@ class CWNano extends Nano { void onStartup() { // monero_wallet_api.onStartup(); } + + @override + Object createNanoTransactionCredentials(List outputs) { + return NanoTransactionCredentials( + outputs + .map((out) => OutputInfo( + fiatAmount: out.fiatAmount, + cryptoAmount: out.cryptoAmount, + address: out.address, + note: out.note, + sendAll: out.sendAll, + extractedAddress: out.extractedAddress, + isParsedAddress: out.isParsedAddress, + formattedCryptoAmount: out.formattedCryptoAmount, + )) + .toList(), + ); + } } diff --git a/lib/nano/nano.dart b/lib/nano/nano.dart index 714021c3d..cf7befdd6 100644 --- a/lib/nano/nano.dart +++ b/lib/nano/nano.dart @@ -1,3 +1,6 @@ +import 'package:cw_core/crypto_currency.dart'; +import 'package:cake_wallet/view_model/send/output.dart'; +import 'package:cw_core/output_info.dart'; import 'package:cw_nano/nano_wallet.dart'; import 'package:cw_nano/nano_wallet_info.dart'; import 'package:cw_nano/nano_wallet_service.dart'; @@ -9,6 +12,7 @@ import 'package:cw_core/wallet_service.dart'; import 'package:hive/hive.dart'; import 'package:cw_nano/nano_balance.dart'; import 'package:cw_nano/nano_wallet_creation_credentials.dart'; +import 'package:cw_nano/nano_transaction_credentials.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; @@ -52,9 +56,9 @@ abstract class Nano { WalletCredentials createNanoRestoreWalletFromSeedCredentials({ required String name, - required String mnemonic, required String password, - required DerivationType derivationType, + required String mnemonic, + DerivationType? derivationType, }); String getTransactionAddress(Object wallet, int accountIndex, int addressIndex); @@ -62,6 +66,8 @@ abstract class Nano { void onStartup(); List getNanoWordList(String language); + + Object createNanoTransactionCredentials(List outputs); } abstract class NanoAccountList { diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index 894f01e15..f74408acd 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -1,6 +1,7 @@ import 'package:cake_wallet/entities/priority_for_wallet_type.dart'; import 'package:cake_wallet/entities/transaction_description.dart'; import 'package:cake_wallet/ethereum/ethereum.dart'; +import 'package:cake_wallet/nano/nano.dart'; import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart'; import 'package:cw_core/transaction_priority.dart'; import 'package:cake_wallet/view_model/send/output.dart'; @@ -32,13 +33,8 @@ part 'send_view_model.g.dart'; class SendViewModel = SendViewModelBase with _$SendViewModel; abstract class SendViewModelBase with Store { - SendViewModelBase( - this._wallet, - this._settingsStore, - this.sendTemplateViewModel, - this._fiatConversationStore, - this.balanceViewModel, - this.transactionDescriptionBox) + SendViewModelBase(this._wallet, this._settingsStore, this.sendTemplateViewModel, + this._fiatConversationStore, this.balanceViewModel, this.transactionDescriptionBox) : state = InitialExecutionState(), currencies = _wallet.balance.keys.toList(), selectedCryptoCurrency = _wallet.currency, @@ -52,7 +48,8 @@ abstract class SendViewModelBase with Store { _settingsStore.priority[_wallet.type] = priorities.first; } - outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency)); + outputs + .add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency)); } @observable @@ -62,7 +59,8 @@ abstract class SendViewModelBase with Store { @action void addOutput() { - outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency)); + outputs + .add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency)); } @action @@ -149,13 +147,11 @@ abstract class SendViewModelBase with Store { @computed String get pendingTransactionFiatAmountFormatted => - isFiatDisabled ? '' : pendingTransactionFiatAmount + - ' ' + fiat.title; + isFiatDisabled ? '' : pendingTransactionFiatAmount + ' ' + fiat.title; @computed String get pendingTransactionFeeFiatAmountFormatted => - isFiatDisabled ? '' : pendingTransactionFeeFiatAmount + - ' ' + fiat.title; + isFiatDisabled ? '' : pendingTransactionFeeFiatAmount + ' ' + fiat.title; @computed bool get isReadyForSend => _wallet.syncStatus is SyncedSyncStatus; @@ -176,9 +172,8 @@ abstract class SendViewModelBase with Store { bool get hasMultiRecipient => _wallet.type != WalletType.haven; - bool get hasYat => outputs.any((out) => - out.isParsedAddress && - out.parsedAddress.parseFrom == ParseFrom.yatRecord); + bool get hasYat => outputs + .any((out) => out.isParsedAddress && out.parsedAddress.parseFrom == ParseFrom.yatRecord); WalletType get walletType => _wallet.type; @@ -236,11 +231,9 @@ abstract class SendViewModelBase with Store { if (pendingTransaction!.id.isNotEmpty) { _settingsStore.shouldSaveRecipientAddress ? await transactionDescriptionBox.add(TransactionDescription( - id: pendingTransaction!.id, - recipientAddress: address, - transactionNote: note)) - : await transactionDescriptionBox.add(TransactionDescription( - id: pendingTransaction!.id, transactionNote: note)); + id: pendingTransaction!.id, recipientAddress: address, transactionNote: note)) + : await transactionDescriptionBox + .add(TransactionDescription(id: pendingTransaction!.id, transactionNote: note)); } state = TransactionCommitted(); @@ -278,8 +271,8 @@ abstract class SendViewModelBase with Store { throw Exception('Priority is null for wallet type: ${_wallet.type}'); } - return monero!.createMoneroTransactionCreationCredentials( - outputs: outputs, priority: priority); + return monero! + .createMoneroTransactionCreationCredentials(outputs: outputs, priority: priority); case WalletType.haven: final priority = _settingsStore.priority[_wallet.type]; @@ -296,8 +289,12 @@ abstract class SendViewModelBase with Store { throw Exception('Priority is null for wallet type: ${_wallet.type}'); } - return ethereum!.createEthereumTransactionCredentials( - outputs, priority: priority, currency: selectedCryptoCurrency); + return ethereum!.createEthereumTransactionCredentials(outputs, + priority: priority, currency: selectedCryptoCurrency); + case WalletType.nano: + return nano!.createNanoTransactionCredentials( + outputs, + ); default: throw Exception('Unexpected wallet type: ${_wallet.type}'); } @@ -319,10 +316,8 @@ abstract class SendViewModelBase with Store { currency.toLowerCase() == _wallet.currency.title.toLowerCase(); @action - void onClose() => - _settingsStore.fiatCurrency = fiatFromSettings; + void onClose() => _settingsStore.fiatCurrency = fiatFromSettings; @action - void setFiatCurrency(FiatCurrency fiat) => - _settingsStore.fiatCurrency = fiat; + void setFiatCurrency(FiatCurrency fiat) => _settingsStore.fiatCurrency = fiat; } diff --git a/lib/view_model/wallet_keys_view_model.dart b/lib/view_model/wallet_keys_view_model.dart index 6b77a43b3..b68a1ab70 100644 --- a/lib/view_model/wallet_keys_view_model.dart +++ b/lib/view_model/wallet_keys_view_model.dart @@ -118,6 +118,10 @@ abstract class WalletKeysViewModelBase with Store { return 'litecoin-wallet'; case WalletType.haven: return 'haven-wallet'; + case WalletType.nano: + return 'nano-wallet'; + case WalletType.banano: + return 'banano-wallet'; default: throw Exception('Unexpected wallet type: ${_appStore.wallet!.toString()}'); } diff --git a/lib/view_model/wallet_restore_view_model.dart b/lib/view_model/wallet_restore_view_model.dart index 7e9256316..9f19dcc3c 100644 --- a/lib/view_model/wallet_restore_view_model.dart +++ b/lib/view_model/wallet_restore_view_model.dart @@ -77,13 +77,11 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { return ethereum!.createEthereumRestoreWalletFromSeedCredentials( name: name, mnemonic: seed, password: password); case WalletType.nano: - // default to bip39 for now: - final DerivationType derivationType = DerivationType.bip39; return nano!.createNanoRestoreWalletFromSeedCredentials( name: name, mnemonic: seed, password: password, - derivationType: derivationType, + derivationType: null, ); default: break; diff --git a/tool/configure.dart b/tool/configure.dart index 3ccf73776..1625624dd 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -585,10 +585,12 @@ import 'package:cw_nano/nano_wallet_info.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/wallet_service.dart'; +import 'package:cw_core/output_info.dart'; import 'package:hive/hive.dart'; import 'package:cw_nano/api/wallet.dart' as nano_wallet_api; import 'package:cw_nano/nano_balance.dart'; import 'package:cw_nano/nano_wallet_creation_credentials.dart'; +import 'package:cw_nano/nano_transaction_credentials.dart'; """; const nanoCwPart = "part 'cw_nano.dart';"; const nanoContent = """ @@ -608,9 +610,9 @@ abstract class Nano { WalletCredentials createNanoRestoreWalletFromSeedCredentials({ required String name, - required String mnemonic, required String password, - required DerivationType derivationType, + required String mnemonic, + DerivationType? derivationType, }); String getTransactionAddress(Object wallet, int accountIndex, int addressIndex); @@ -618,6 +620,8 @@ abstract class Nano { void onStartup(); List getNanoWordList(String language); + + Object createNanoTransactionCredentials(List outputs); } abstract class NanoAccountList {