From adfe3e181e5ae4ec27305de3ef758b39ba901c3b Mon Sep 17 00:00:00 2001 From: julian Date: Thu, 14 Sep 2023 17:34:01 -0600 Subject: [PATCH] WIP restructure w/moving from hive to isar for wallets and using coinlib --- lib/db/isar/main_db.dart | 37 + lib/models/balance.dart | 15 + lib/models/tx_info.dart | 11 +- lib/wallets/coin/bip39_hd_currency.dart | 22 + lib/wallets/coin/coin_params.dart | 29 + lib/wallets/coin/coins/bitcoin.dart | 115 + lib/wallets/coin/crypto_currency.dart | 16 + lib/wallets/isar_models/wallet_info.dart | 149 ++ lib/wallets/isar_models/wallet_info.g.dart | 1900 +++++++++++++++++ lib/wallets/models/tx_data.dart | 106 + lib/wallets/models/tx_recipient.dart | 11 + lib/wallets/wallet/bip39_hd_wallet.dart | 152 ++ lib/wallets/wallet/cryptonote_wallet.dart | 33 + .../wallet/private_key_based_wallet.dart | 33 + lib/wallets/wallet/wallet.dart | 174 ++ .../wallet_mixins/electrumx_mixin.dart | 3 + lib/wallets/wallets_service.dart | 15 + pubspec.lock | 16 + pubspec.yaml | 1 + scripts/dev/build_runner.sh | 8 + .../coins/firo/firo_wallet_test.mocks.dart | 198 +- .../transaction_card_test.mocks.dart | 54 +- 22 files changed, 2994 insertions(+), 104 deletions(-) create mode 100644 lib/wallets/coin/bip39_hd_currency.dart create mode 100644 lib/wallets/coin/coin_params.dart create mode 100644 lib/wallets/coin/coins/bitcoin.dart create mode 100644 lib/wallets/coin/crypto_currency.dart create mode 100644 lib/wallets/isar_models/wallet_info.dart create mode 100644 lib/wallets/isar_models/wallet_info.g.dart create mode 100644 lib/wallets/models/tx_data.dart create mode 100644 lib/wallets/models/tx_recipient.dart create mode 100644 lib/wallets/wallet/bip39_hd_wallet.dart create mode 100644 lib/wallets/wallet/cryptonote_wallet.dart create mode 100644 lib/wallets/wallet/private_key_based_wallet.dart create mode 100644 lib/wallets/wallet/wallet.dart create mode 100644 lib/wallets/wallet_mixins/electrumx_mixin.dart create mode 100644 lib/wallets/wallets_service.dart create mode 100755 scripts/dev/build_runner.sh diff --git a/lib/db/isar/main_db.dart b/lib/db/isar/main_db.dart index 9465de12b..89f41aaec 100644 --- a/lib/db/isar/main_db.dart +++ b/lib/db/isar/main_db.dart @@ -20,6 +20,7 @@ import 'package:stackwallet/models/isar/stack_theme.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/stack_file_system.dart'; +import 'package:stackwallet/wallets/isar_models/wallet_info.dart'; import 'package:tuple/tuple.dart'; part '../queries/queries.dart'; @@ -57,6 +58,7 @@ class MainDB { ContactEntrySchema, OrdinalSchema, LelantusCoinSchema, + WalletInfoSchema, ], directory: (await StackFileSystem.applicationIsarDirectory()).path, // inspector: kDebugMode, @@ -67,6 +69,41 @@ class MainDB { return true; } + Future putWalletInfo(WalletInfo walletInfo) async { + try { + await isar.writeTxn(() async { + await isar.walletInfo.put(walletInfo); + }); + } catch (e) { + throw MainDBException("failed putWalletInfo()", e); + } + } + + Future updateWalletInfo(WalletInfo walletInfo) async { + try { + await isar.writeTxn(() async { + final info = await isar.walletInfo + .where() + .walletIdEqualTo(walletInfo.walletId) + .findFirst(); + if (info == null) { + throw Exception("updateWalletInfo() called with new WalletInfo." + " Use putWalletInfo()"); + } + + await isar.walletInfo.deleteByWalletId(walletInfo.walletId); + await isar.walletInfo.put(walletInfo); + }); + } catch (e) { + throw MainDBException("failed updateWalletInfo()", e); + } + } + + // TODO refactor this elsewhere as it not only interacts with MainDB's isar + Future deleteWallet({required String walletId}) async { + // + } + // contact entries List getContactEntries() { return isar.contactEntrys.where().sortByName().findAllSync(); diff --git a/lib/models/balance.dart b/lib/models/balance.dart index a77e87834..9f4b36a1c 100644 --- a/lib/models/balance.dart +++ b/lib/models/balance.dart @@ -11,6 +11,7 @@ import 'dart:convert'; import 'package:stackwallet/utilities/amount/amount.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; class Balance { final Amount total; @@ -25,6 +26,20 @@ class Balance { required this.pendingSpendable, }); + factory Balance.zeroForCoin({required Coin coin}) { + final amount = Amount( + rawValue: BigInt.zero, + fractionDigits: coin.decimals, + ); + + return Balance( + total: amount, + spendable: amount, + blockedTotal: amount, + pendingSpendable: amount, + ); + } + String toJsonIgnoreCoin() => jsonEncode({ "total": total.toJsonString(), "spendable": spendable.toJsonString(), diff --git a/lib/models/tx_info.dart b/lib/models/tx_info.dart index 88eebde0d..ddb361979 100644 --- a/lib/models/tx_info.dart +++ b/lib/models/tx_info.dart @@ -10,6 +10,7 @@ import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; +import 'package:stackwallet/wallets/models/tx_recipient.dart'; // TODO use something like this instead of Map transactionObject @@ -43,13 +44,3 @@ class TxInfo { recipients: recipients ?? this.recipients, ); } - -class TxRecipient { - final String address; - final Amount amount; - - TxRecipient({ - required this.address, - required this.amount, - }); -} diff --git a/lib/wallets/coin/bip39_hd_currency.dart b/lib/wallets/coin/bip39_hd_currency.dart new file mode 100644 index 000000000..cf29f1e57 --- /dev/null +++ b/lib/wallets/coin/bip39_hd_currency.dart @@ -0,0 +1,22 @@ +import 'package:coinlib/coinlib.dart' as coinlib; +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; +import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; +import 'package:stackwallet/wallets/coin/crypto_currency.dart'; + +abstract class Bip39HDCurrency extends CryptoCurrency { + Bip39HDCurrency(super.network); + + coinlib.NetworkParams get networkParams; + + String constructDerivePath({ + required DerivePathType derivePathType, + int account = 0, + required int chain, + required int index, + }); + + ({coinlib.Address address, AddressType addressType}) getAddressForPublicKey({ + required coinlib.ECPublicKey publicKey, + required DerivePathType derivePathType, + }); +} diff --git a/lib/wallets/coin/coin_params.dart b/lib/wallets/coin/coin_params.dart new file mode 100644 index 000000000..2c0dc1bb6 --- /dev/null +++ b/lib/wallets/coin/coin_params.dart @@ -0,0 +1,29 @@ +import 'package:coinlib/coinlib.dart'; + +abstract class CoinParams { + static const bitcoin = BitcoinParams(); +} + +class BitcoinParams { + const BitcoinParams(); + + final NetworkParams mainNet = const NetworkParams( + wifPrefix: 0x80, + p2pkhPrefix: 0x00, + p2shPrefix: 0x05, + privHDPrefix: 0x0488ade4, + pubHDPrefix: 0x0488b21e, + bech32Hrp: "bc", + messagePrefix: '\x18Bitcoin Signed Message:\n', + ); + + final NetworkParams testNet = const NetworkParams( + wifPrefix: 0xef, + p2pkhPrefix: 0x6f, + p2shPrefix: 0xc4, + privHDPrefix: 0x04358394, + pubHDPrefix: 0x043587cf, + bech32Hrp: "tb", + messagePrefix: "\x18Bitcoin Signed Message:\n", + ); +} diff --git a/lib/wallets/coin/coins/bitcoin.dart b/lib/wallets/coin/coins/bitcoin.dart new file mode 100644 index 000000000..a6c81a2e9 --- /dev/null +++ b/lib/wallets/coin/coins/bitcoin.dart @@ -0,0 +1,115 @@ +import 'package:coinlib/coinlib.dart' as coinlib; +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; +import 'package:stackwallet/wallets/coin/bip39_hd_currency.dart'; +import 'package:stackwallet/wallets/coin/coin_params.dart'; +import 'package:stackwallet/wallets/coin/crypto_currency.dart'; + +class Bitcoin extends Bip39HDCurrency { + Bitcoin(super.network) { + switch (network) { + case CryptoCurrencyNetwork.main: + coin = Coin.bitcoin; + case CryptoCurrencyNetwork.test: + coin = Coin.bitcoinTestNet; + default: + throw Exception("Unsupported network: $network"); + } + } + + @override + coinlib.NetworkParams get networkParams { + switch (network) { + case CryptoCurrencyNetwork.main: + return CoinParams.bitcoin.mainNet; + case CryptoCurrencyNetwork.test: + return CoinParams.bitcoin.testNet; + default: + throw Exception("Unsupported network: $network"); + } + } + + @override + String constructDerivePath({ + required DerivePathType derivePathType, + int account = 0, + required int chain, + required int index, + }) { + String coinType; + + if (networkParams.wifPrefix == CoinParams.bitcoin.mainNet.wifPrefix) { + coinType = "0"; // btc mainnet + } else if (networkParams.wifPrefix == + CoinParams.bitcoin.testNet.wifPrefix) { + coinType = "1"; // btc testnet + } else { + throw Exception("Invalid Bitcoin network wif used!"); + } + + int purpose; + switch (derivePathType) { + case DerivePathType.bip44: + purpose = 44; + break; + case DerivePathType.bip49: + purpose = 49; + break; + case DerivePathType.bip84: + purpose = 84; + break; + default: + throw Exception("DerivePathType $derivePathType not supported"); + } + + return "m/$purpose'/$coinType'/$account'/$chain/$index"; + } + + ({coinlib.Address address, AddressType addressType}) getAddressForPublicKey({ + required coinlib.ECPublicKey publicKey, + required DerivePathType derivePathType, + }) { + switch (derivePathType) { + case DerivePathType.bip44: + final addr = coinlib.P2PKHAddress.fromPublicKey( + publicKey, + version: networkParams.p2pkhPrefix, + ); + + return (address: addr, addressType: AddressType.p2sh); + break; + case DerivePathType.bip49: + // addressString = P2SH( + // data: PaymentData( + // redeem: P2WPKH(data: data, network: _network).data), + // network: _network) + // .data + // .address!; + + // todo ?????????????????? Does not match with current BTC + final adr = coinlib.P2WPKHAddress.fromPublicKey( + publicKey, + hrp: networkParams.bech32Hrp, + ); + final addr = coinlib.P2SHAddress.fromHash( + adr.program.pkHash, + version: networkParams.p2shPrefix, + ); + + // TODO ?????????????? + return (address: addr, addressType: AddressType.p2sh); + + case DerivePathType.bip84: + final addr = coinlib.P2WPKHAddress.fromPublicKey( + publicKey, + hrp: networkParams.bech32Hrp, + ); + + return (address: addr, addressType: AddressType.p2wpkh); + break; + default: + throw Exception("DerivePathType $derivePathType not supported"); + } + } +} diff --git a/lib/wallets/coin/crypto_currency.dart b/lib/wallets/coin/crypto_currency.dart new file mode 100644 index 000000000..ae8ce8ce1 --- /dev/null +++ b/lib/wallets/coin/crypto_currency.dart @@ -0,0 +1,16 @@ +import 'package:stackwallet/utilities/enums/coin_enum.dart'; + +enum CryptoCurrencyNetwork { + main, + test, + stage; +} + +abstract class CryptoCurrency { + @Deprecated("Should eventually move away from Coin enum") + late final Coin coin; + + final CryptoCurrencyNetwork network; + + CryptoCurrency(this.network); +} diff --git a/lib/wallets/isar_models/wallet_info.dart b/lib/wallets/isar_models/wallet_info.dart new file mode 100644 index 000000000..aa5360b74 --- /dev/null +++ b/lib/wallets/isar_models/wallet_info.dart @@ -0,0 +1,149 @@ +import 'dart:convert'; + +import 'package:isar/isar.dart'; +import 'package:stackwallet/models/balance.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; + +part 'wallet_info.g.dart'; + +@Collection(accessor: "walletInfo") +class WalletInfo { + Id id = Isar.autoIncrement; + + @Index(unique: true, replace: false) + final String walletId; + + final String name; + + @enumerated + final WalletType walletType; + + @enumerated + final AddressType mainAddressType; + + /// Only exposed for Isar. Use the [cachedBalance] getter. + // Only exposed for isar as Amount cannot be stored in isar easily + final String? cachedBalanceString; + + /// Only exposed for Isar. Use the [coin] getter. + // Only exposed for isar to avoid dealing with storing enums as Coin can change + final String coinName; + + final bool isFavourite; + + /// User set favourites ordering. No restrictions are placed on uniqueness. + /// Reordering logic in the ui code should ensure this is unique. + final int favouriteOrderIndex; + + /// Wallets without this flag set to true should be deleted on next app run + /// and should not be displayed in the ui. + final bool isMnemonicVerified; + + /// The highest block height the wallet has scanned. + final int cachedChainHeight; + + /// Wallet creation chain height. Applies to select coin only. + final int creationHeight; + + /// Wallet restore chain height. Applies to select coin only. + final int restoreHeight; + + //============================================================================ + + @ignore + Coin get coin => Coin.values.byName(coinName); + + @ignore + Balance get cachedBalance { + if (cachedBalanceString == null) { + return Balance.zeroForCoin(coin: coin); + } else { + return Balance.fromJson(cachedBalanceString!, coin.decimals); + } + } + + WalletInfo({ + required this.coinName, + required this.walletId, + required this.name, + required this.walletType, + required this.mainAddressType, + this.isFavourite = false, + this.favouriteOrderIndex = 0, + this.cachedChainHeight = 0, + this.creationHeight = 0, + this.restoreHeight = 0, + this.isMnemonicVerified = false, + this.cachedBalanceString, + }) : assert( + Coin.values.map((e) => e.name).contains(coinName), + ); + + WalletInfo copyWith({ + String? coinName, + String? name, + bool? isFavourite, + int? favouriteOrderIndex, + int? cachedChainHeight, + int? creationHeight, + int? restoreHeight, + bool? isMnemonicVerified, + String? cachedBalanceString, + }) { + return WalletInfo( + coinName: coinName ?? this.coinName, + walletId: walletId, + name: name ?? this.name, + walletType: walletType, + mainAddressType: mainAddressType, + isFavourite: isFavourite ?? this.isFavourite, + favouriteOrderIndex: favouriteOrderIndex ?? this.favouriteOrderIndex, + cachedChainHeight: cachedChainHeight ?? this.cachedChainHeight, + creationHeight: creationHeight ?? this.creationHeight, + restoreHeight: restoreHeight ?? this.restoreHeight, + isMnemonicVerified: isMnemonicVerified ?? this.isMnemonicVerified, + cachedBalanceString: cachedBalanceString ?? this.cachedBalanceString, + )..id = id; + } + + @Deprecated("Legacy support") + factory WalletInfo.fromJson(Map jsonObject, + WalletType walletType, AddressType mainAddressType) { + final coin = Coin.values.byName(jsonObject["coin"] as String); + return WalletInfo( + coinName: coin.name, + walletId: jsonObject["id"] as String, + name: jsonObject["name"] as String, + walletType: walletType, + mainAddressType: mainAddressType, + ); + } + + @Deprecated("Legacy support") + Map toMap() { + return { + "name": name, + "id": walletId, + "coin": coin.name, + }; + } + + @Deprecated("Legacy support") + String toJsonString() { + return jsonEncode(toMap()); + } + + @override + String toString() { + return "WalletInfo: ${toJsonString()}"; + } +} + +// Used in Isar db and stored there as int indexes so adding/removing values +// in this definition should be done extremely carefully in production +enum WalletType { + bip39, + cryptonote, + privateKeyBased; +} diff --git a/lib/wallets/isar_models/wallet_info.g.dart b/lib/wallets/isar_models/wallet_info.g.dart new file mode 100644 index 000000000..3395e9277 --- /dev/null +++ b/lib/wallets/isar_models/wallet_info.g.dart @@ -0,0 +1,1900 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'wallet_info.dart'; + +// ************************************************************************** +// IsarCollectionGenerator +// ************************************************************************** + +// coverage:ignore-file +// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters + +extension GetWalletInfoCollection on Isar { + IsarCollection get walletInfo => this.collection(); +} + +const WalletInfoSchema = CollectionSchema( + name: r'WalletInfo', + id: -2861501434900022153, + properties: { + r'cachedBalanceString': PropertySchema( + id: 0, + name: r'cachedBalanceString', + type: IsarType.string, + ), + r'cachedChainHeight': PropertySchema( + id: 1, + name: r'cachedChainHeight', + type: IsarType.long, + ), + r'coinName': PropertySchema( + id: 2, + name: r'coinName', + type: IsarType.string, + ), + r'creationHeight': PropertySchema( + id: 3, + name: r'creationHeight', + type: IsarType.long, + ), + r'favouriteOrderIndex': PropertySchema( + id: 4, + name: r'favouriteOrderIndex', + type: IsarType.long, + ), + r'isFavourite': PropertySchema( + id: 5, + name: r'isFavourite', + type: IsarType.bool, + ), + r'isMnemonicVerified': PropertySchema( + id: 6, + name: r'isMnemonicVerified', + type: IsarType.bool, + ), + r'mainAddressType': PropertySchema( + id: 7, + name: r'mainAddressType', + type: IsarType.byte, + enumMap: _WalletInfomainAddressTypeEnumValueMap, + ), + r'name': PropertySchema( + id: 8, + name: r'name', + type: IsarType.string, + ), + r'restoreHeight': PropertySchema( + id: 9, + name: r'restoreHeight', + type: IsarType.long, + ), + r'walletId': PropertySchema( + id: 10, + name: r'walletId', + type: IsarType.string, + ), + r'walletType': PropertySchema( + id: 11, + name: r'walletType', + type: IsarType.byte, + enumMap: _WalletInfowalletTypeEnumValueMap, + ) + }, + estimateSize: _walletInfoEstimateSize, + serialize: _walletInfoSerialize, + deserialize: _walletInfoDeserialize, + deserializeProp: _walletInfoDeserializeProp, + idName: r'id', + indexes: { + r'walletId': IndexSchema( + id: -1783113319798776304, + name: r'walletId', + unique: true, + replace: false, + properties: [ + IndexPropertySchema( + name: r'walletId', + type: IndexType.hash, + caseSensitive: true, + ) + ], + ) + }, + links: {}, + embeddedSchemas: {}, + getId: _walletInfoGetId, + getLinks: _walletInfoGetLinks, + attach: _walletInfoAttach, + version: '3.0.5', +); + +int _walletInfoEstimateSize( + WalletInfo object, + List offsets, + Map> allOffsets, +) { + var bytesCount = offsets.last; + { + final value = object.cachedBalanceString; + if (value != null) { + bytesCount += 3 + value.length * 3; + } + } + bytesCount += 3 + object.coinName.length * 3; + bytesCount += 3 + object.name.length * 3; + bytesCount += 3 + object.walletId.length * 3; + return bytesCount; +} + +void _walletInfoSerialize( + WalletInfo object, + IsarWriter writer, + List offsets, + Map> allOffsets, +) { + writer.writeString(offsets[0], object.cachedBalanceString); + writer.writeLong(offsets[1], object.cachedChainHeight); + writer.writeString(offsets[2], object.coinName); + writer.writeLong(offsets[3], object.creationHeight); + writer.writeLong(offsets[4], object.favouriteOrderIndex); + writer.writeBool(offsets[5], object.isFavourite); + writer.writeBool(offsets[6], object.isMnemonicVerified); + writer.writeByte(offsets[7], object.mainAddressType.index); + writer.writeString(offsets[8], object.name); + writer.writeLong(offsets[9], object.restoreHeight); + writer.writeString(offsets[10], object.walletId); + writer.writeByte(offsets[11], object.walletType.index); +} + +WalletInfo _walletInfoDeserialize( + Id id, + IsarReader reader, + List offsets, + Map> allOffsets, +) { + final object = WalletInfo( + cachedBalanceString: reader.readStringOrNull(offsets[0]), + cachedChainHeight: reader.readLongOrNull(offsets[1]) ?? 0, + coinName: reader.readString(offsets[2]), + creationHeight: reader.readLongOrNull(offsets[3]) ?? 0, + favouriteOrderIndex: reader.readLongOrNull(offsets[4]) ?? 0, + isFavourite: reader.readBoolOrNull(offsets[5]) ?? false, + isMnemonicVerified: reader.readBoolOrNull(offsets[6]) ?? false, + mainAddressType: _WalletInfomainAddressTypeValueEnumMap[ + reader.readByteOrNull(offsets[7])] ?? + AddressType.p2pkh, + name: reader.readString(offsets[8]), + restoreHeight: reader.readLongOrNull(offsets[9]) ?? 0, + walletId: reader.readString(offsets[10]), + walletType: + _WalletInfowalletTypeValueEnumMap[reader.readByteOrNull(offsets[11])] ?? + WalletType.bip39, + ); + object.id = id; + return object; +} + +P _walletInfoDeserializeProp

( + IsarReader reader, + int propertyId, + int offset, + Map> allOffsets, +) { + switch (propertyId) { + case 0: + return (reader.readStringOrNull(offset)) as P; + case 1: + return (reader.readLongOrNull(offset) ?? 0) as P; + case 2: + return (reader.readString(offset)) as P; + case 3: + return (reader.readLongOrNull(offset) ?? 0) as P; + case 4: + return (reader.readLongOrNull(offset) ?? 0) as P; + case 5: + return (reader.readBoolOrNull(offset) ?? false) as P; + case 6: + return (reader.readBoolOrNull(offset) ?? false) as P; + case 7: + return (_WalletInfomainAddressTypeValueEnumMap[ + reader.readByteOrNull(offset)] ?? + AddressType.p2pkh) as P; + case 8: + return (reader.readString(offset)) as P; + case 9: + return (reader.readLongOrNull(offset) ?? 0) as P; + case 10: + return (reader.readString(offset)) as P; + case 11: + return (_WalletInfowalletTypeValueEnumMap[ + reader.readByteOrNull(offset)] ?? + WalletType.bip39) as P; + default: + throw IsarError('Unknown property with id $propertyId'); + } +} + +const _WalletInfomainAddressTypeEnumValueMap = { + 'p2pkh': 0, + 'p2sh': 1, + 'p2wpkh': 2, + 'cryptonote': 3, + 'mimbleWimble': 4, + 'unknown': 5, + 'nonWallet': 6, + 'ethereum': 7, + 'nano': 8, + 'banano': 9, +}; +const _WalletInfomainAddressTypeValueEnumMap = { + 0: AddressType.p2pkh, + 1: AddressType.p2sh, + 2: AddressType.p2wpkh, + 3: AddressType.cryptonote, + 4: AddressType.mimbleWimble, + 5: AddressType.unknown, + 6: AddressType.nonWallet, + 7: AddressType.ethereum, + 8: AddressType.nano, + 9: AddressType.banano, +}; +const _WalletInfowalletTypeEnumValueMap = { + 'bip39': 0, + 'cryptonote': 1, + 'privateKeyBased': 2, +}; +const _WalletInfowalletTypeValueEnumMap = { + 0: WalletType.bip39, + 1: WalletType.cryptonote, + 2: WalletType.privateKeyBased, +}; + +Id _walletInfoGetId(WalletInfo object) { + return object.id; +} + +List> _walletInfoGetLinks(WalletInfo object) { + return []; +} + +void _walletInfoAttach(IsarCollection col, Id id, WalletInfo object) { + object.id = id; +} + +extension WalletInfoByIndex on IsarCollection { + Future getByWalletId(String walletId) { + return getByIndex(r'walletId', [walletId]); + } + + WalletInfo? getByWalletIdSync(String walletId) { + return getByIndexSync(r'walletId', [walletId]); + } + + Future deleteByWalletId(String walletId) { + return deleteByIndex(r'walletId', [walletId]); + } + + bool deleteByWalletIdSync(String walletId) { + return deleteByIndexSync(r'walletId', [walletId]); + } + + Future> getAllByWalletId(List walletIdValues) { + final values = walletIdValues.map((e) => [e]).toList(); + return getAllByIndex(r'walletId', values); + } + + List getAllByWalletIdSync(List walletIdValues) { + final values = walletIdValues.map((e) => [e]).toList(); + return getAllByIndexSync(r'walletId', values); + } + + Future deleteAllByWalletId(List walletIdValues) { + final values = walletIdValues.map((e) => [e]).toList(); + return deleteAllByIndex(r'walletId', values); + } + + int deleteAllByWalletIdSync(List walletIdValues) { + final values = walletIdValues.map((e) => [e]).toList(); + return deleteAllByIndexSync(r'walletId', values); + } + + Future putByWalletId(WalletInfo object) { + return putByIndex(r'walletId', object); + } + + Id putByWalletIdSync(WalletInfo object, {bool saveLinks = true}) { + return putByIndexSync(r'walletId', object, saveLinks: saveLinks); + } + + Future> putAllByWalletId(List objects) { + return putAllByIndex(r'walletId', objects); + } + + List putAllByWalletIdSync(List objects, + {bool saveLinks = true}) { + return putAllByIndexSync(r'walletId', objects, saveLinks: saveLinks); + } +} + +extension WalletInfoQueryWhereSort + on QueryBuilder { + QueryBuilder anyId() { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(const IdWhereClause.any()); + }); + } +} + +extension WalletInfoQueryWhere + on QueryBuilder { + QueryBuilder idEqualTo(Id id) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IdWhereClause.between( + lower: id, + upper: id, + )); + }); + } + + QueryBuilder idNotEqualTo(Id id) { + return QueryBuilder.apply(this, (query) { + if (query.whereSort == Sort.asc) { + return query + .addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: false), + ) + .addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: false), + ); + } else { + return query + .addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: false), + ) + .addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: false), + ); + } + }); + } + + QueryBuilder idGreaterThan(Id id, + {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: include), + ); + }); + } + + QueryBuilder idLessThan(Id id, + {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: include), + ); + }); + } + + QueryBuilder idBetween( + Id lowerId, + Id upperId, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IdWhereClause.between( + lower: lowerId, + includeLower: includeLower, + upper: upperId, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder walletIdEqualTo( + String walletId) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IndexWhereClause.equalTo( + indexName: r'walletId', + value: [walletId], + )); + }); + } + + QueryBuilder walletIdNotEqualTo( + String walletId) { + return QueryBuilder.apply(this, (query) { + if (query.whereSort == Sort.asc) { + return query + .addWhereClause(IndexWhereClause.between( + indexName: r'walletId', + lower: [], + upper: [walletId], + includeUpper: false, + )) + .addWhereClause(IndexWhereClause.between( + indexName: r'walletId', + lower: [walletId], + includeLower: false, + upper: [], + )); + } else { + return query + .addWhereClause(IndexWhereClause.between( + indexName: r'walletId', + lower: [walletId], + includeLower: false, + upper: [], + )) + .addWhereClause(IndexWhereClause.between( + indexName: r'walletId', + lower: [], + upper: [walletId], + includeUpper: false, + )); + } + }); + } +} + +extension WalletInfoQueryFilter + on QueryBuilder { + QueryBuilder + cachedBalanceStringIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'cachedBalanceString', + )); + }); + } + + QueryBuilder + cachedBalanceStringIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'cachedBalanceString', + )); + }); + } + + QueryBuilder + cachedBalanceStringEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'cachedBalanceString', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + cachedBalanceStringGreaterThan( + String? value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'cachedBalanceString', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + cachedBalanceStringLessThan( + String? value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'cachedBalanceString', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + cachedBalanceStringBetween( + String? lower, + String? upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'cachedBalanceString', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + cachedBalanceStringStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'cachedBalanceString', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + cachedBalanceStringEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'cachedBalanceString', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + cachedBalanceStringContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'cachedBalanceString', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + cachedBalanceStringMatches(String pattern, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'cachedBalanceString', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + cachedBalanceStringIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'cachedBalanceString', + value: '', + )); + }); + } + + QueryBuilder + cachedBalanceStringIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'cachedBalanceString', + value: '', + )); + }); + } + + QueryBuilder + cachedChainHeightEqualTo(int value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'cachedChainHeight', + value: value, + )); + }); + } + + QueryBuilder + cachedChainHeightGreaterThan( + int value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'cachedChainHeight', + value: value, + )); + }); + } + + QueryBuilder + cachedChainHeightLessThan( + int value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'cachedChainHeight', + value: value, + )); + }); + } + + QueryBuilder + cachedChainHeightBetween( + int lower, + int upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'cachedChainHeight', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder coinNameEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'coinName', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + coinNameGreaterThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'coinName', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder coinNameLessThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'coinName', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder coinNameBetween( + String lower, + String upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'coinName', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + coinNameStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'coinName', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder coinNameEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'coinName', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder coinNameContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'coinName', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder coinNameMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'coinName', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + coinNameIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'coinName', + value: '', + )); + }); + } + + QueryBuilder + coinNameIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'coinName', + value: '', + )); + }); + } + + QueryBuilder + creationHeightEqualTo(int value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'creationHeight', + value: value, + )); + }); + } + + QueryBuilder + creationHeightGreaterThan( + int value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'creationHeight', + value: value, + )); + }); + } + + QueryBuilder + creationHeightLessThan( + int value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'creationHeight', + value: value, + )); + }); + } + + QueryBuilder + creationHeightBetween( + int lower, + int upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'creationHeight', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder + favouriteOrderIndexEqualTo(int value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'favouriteOrderIndex', + value: value, + )); + }); + } + + QueryBuilder + favouriteOrderIndexGreaterThan( + int value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'favouriteOrderIndex', + value: value, + )); + }); + } + + QueryBuilder + favouriteOrderIndexLessThan( + int value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'favouriteOrderIndex', + value: value, + )); + }); + } + + QueryBuilder + favouriteOrderIndexBetween( + int lower, + int upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'favouriteOrderIndex', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder idEqualTo( + Id value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idGreaterThan( + Id value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idLessThan( + Id value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idBetween( + Id lower, + Id upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder + isFavouriteEqualTo(bool value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'isFavourite', + value: value, + )); + }); + } + + QueryBuilder + isMnemonicVerifiedEqualTo(bool value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'isMnemonicVerified', + value: value, + )); + }); + } + + QueryBuilder + mainAddressTypeEqualTo(AddressType value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'mainAddressType', + value: value, + )); + }); + } + + QueryBuilder + mainAddressTypeGreaterThan( + AddressType value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'mainAddressType', + value: value, + )); + }); + } + + QueryBuilder + mainAddressTypeLessThan( + AddressType value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'mainAddressType', + value: value, + )); + }); + } + + QueryBuilder + mainAddressTypeBetween( + AddressType lower, + AddressType upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'mainAddressType', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder nameEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameGreaterThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameLessThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameBetween( + String lower, + String upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'name', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'name', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'name', + value: '', + )); + }); + } + + QueryBuilder nameIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'name', + value: '', + )); + }); + } + + QueryBuilder + restoreHeightEqualTo(int value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'restoreHeight', + value: value, + )); + }); + } + + QueryBuilder + restoreHeightGreaterThan( + int value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'restoreHeight', + value: value, + )); + }); + } + + QueryBuilder + restoreHeightLessThan( + int value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'restoreHeight', + value: value, + )); + }); + } + + QueryBuilder + restoreHeightBetween( + int lower, + int upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'restoreHeight', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder walletIdEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'walletId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + walletIdGreaterThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'walletId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder walletIdLessThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'walletId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder walletIdBetween( + String lower, + String upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'walletId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + walletIdStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'walletId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder walletIdEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'walletId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder walletIdContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'walletId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder walletIdMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'walletId', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + walletIdIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'walletId', + value: '', + )); + }); + } + + QueryBuilder + walletIdIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'walletId', + value: '', + )); + }); + } + + QueryBuilder walletTypeEqualTo( + WalletType value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'walletType', + value: value, + )); + }); + } + + QueryBuilder + walletTypeGreaterThan( + WalletType value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'walletType', + value: value, + )); + }); + } + + QueryBuilder + walletTypeLessThan( + WalletType value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'walletType', + value: value, + )); + }); + } + + QueryBuilder walletTypeBetween( + WalletType lower, + WalletType upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'walletType', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } +} + +extension WalletInfoQueryObject + on QueryBuilder {} + +extension WalletInfoQueryLinks + on QueryBuilder {} + +extension WalletInfoQuerySortBy + on QueryBuilder { + QueryBuilder + sortByCachedBalanceString() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'cachedBalanceString', Sort.asc); + }); + } + + QueryBuilder + sortByCachedBalanceStringDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'cachedBalanceString', Sort.desc); + }); + } + + QueryBuilder sortByCachedChainHeight() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'cachedChainHeight', Sort.asc); + }); + } + + QueryBuilder + sortByCachedChainHeightDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'cachedChainHeight', Sort.desc); + }); + } + + QueryBuilder sortByCoinName() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'coinName', Sort.asc); + }); + } + + QueryBuilder sortByCoinNameDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'coinName', Sort.desc); + }); + } + + QueryBuilder sortByCreationHeight() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'creationHeight', Sort.asc); + }); + } + + QueryBuilder + sortByCreationHeightDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'creationHeight', Sort.desc); + }); + } + + QueryBuilder + sortByFavouriteOrderIndex() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'favouriteOrderIndex', Sort.asc); + }); + } + + QueryBuilder + sortByFavouriteOrderIndexDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'favouriteOrderIndex', Sort.desc); + }); + } + + QueryBuilder sortByIsFavourite() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isFavourite', Sort.asc); + }); + } + + QueryBuilder sortByIsFavouriteDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isFavourite', Sort.desc); + }); + } + + QueryBuilder + sortByIsMnemonicVerified() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isMnemonicVerified', Sort.asc); + }); + } + + QueryBuilder + sortByIsMnemonicVerifiedDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isMnemonicVerified', Sort.desc); + }); + } + + QueryBuilder sortByMainAddressType() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'mainAddressType', Sort.asc); + }); + } + + QueryBuilder + sortByMainAddressTypeDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'mainAddressType', Sort.desc); + }); + } + + QueryBuilder sortByName() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.asc); + }); + } + + QueryBuilder sortByNameDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.desc); + }); + } + + QueryBuilder sortByRestoreHeight() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'restoreHeight', Sort.asc); + }); + } + + QueryBuilder sortByRestoreHeightDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'restoreHeight', Sort.desc); + }); + } + + QueryBuilder sortByWalletId() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'walletId', Sort.asc); + }); + } + + QueryBuilder sortByWalletIdDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'walletId', Sort.desc); + }); + } + + QueryBuilder sortByWalletType() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'walletType', Sort.asc); + }); + } + + QueryBuilder sortByWalletTypeDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'walletType', Sort.desc); + }); + } +} + +extension WalletInfoQuerySortThenBy + on QueryBuilder { + QueryBuilder + thenByCachedBalanceString() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'cachedBalanceString', Sort.asc); + }); + } + + QueryBuilder + thenByCachedBalanceStringDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'cachedBalanceString', Sort.desc); + }); + } + + QueryBuilder thenByCachedChainHeight() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'cachedChainHeight', Sort.asc); + }); + } + + QueryBuilder + thenByCachedChainHeightDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'cachedChainHeight', Sort.desc); + }); + } + + QueryBuilder thenByCoinName() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'coinName', Sort.asc); + }); + } + + QueryBuilder thenByCoinNameDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'coinName', Sort.desc); + }); + } + + QueryBuilder thenByCreationHeight() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'creationHeight', Sort.asc); + }); + } + + QueryBuilder + thenByCreationHeightDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'creationHeight', Sort.desc); + }); + } + + QueryBuilder + thenByFavouriteOrderIndex() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'favouriteOrderIndex', Sort.asc); + }); + } + + QueryBuilder + thenByFavouriteOrderIndexDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'favouriteOrderIndex', Sort.desc); + }); + } + + QueryBuilder thenById() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'id', Sort.asc); + }); + } + + QueryBuilder thenByIdDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'id', Sort.desc); + }); + } + + QueryBuilder thenByIsFavourite() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isFavourite', Sort.asc); + }); + } + + QueryBuilder thenByIsFavouriteDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isFavourite', Sort.desc); + }); + } + + QueryBuilder + thenByIsMnemonicVerified() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isMnemonicVerified', Sort.asc); + }); + } + + QueryBuilder + thenByIsMnemonicVerifiedDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isMnemonicVerified', Sort.desc); + }); + } + + QueryBuilder thenByMainAddressType() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'mainAddressType', Sort.asc); + }); + } + + QueryBuilder + thenByMainAddressTypeDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'mainAddressType', Sort.desc); + }); + } + + QueryBuilder thenByName() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.asc); + }); + } + + QueryBuilder thenByNameDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.desc); + }); + } + + QueryBuilder thenByRestoreHeight() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'restoreHeight', Sort.asc); + }); + } + + QueryBuilder thenByRestoreHeightDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'restoreHeight', Sort.desc); + }); + } + + QueryBuilder thenByWalletId() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'walletId', Sort.asc); + }); + } + + QueryBuilder thenByWalletIdDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'walletId', Sort.desc); + }); + } + + QueryBuilder thenByWalletType() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'walletType', Sort.asc); + }); + } + + QueryBuilder thenByWalletTypeDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'walletType', Sort.desc); + }); + } +} + +extension WalletInfoQueryWhereDistinct + on QueryBuilder { + QueryBuilder distinctByCachedBalanceString( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'cachedBalanceString', + caseSensitive: caseSensitive); + }); + } + + QueryBuilder + distinctByCachedChainHeight() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'cachedChainHeight'); + }); + } + + QueryBuilder distinctByCoinName( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'coinName', caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByCreationHeight() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'creationHeight'); + }); + } + + QueryBuilder + distinctByFavouriteOrderIndex() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'favouriteOrderIndex'); + }); + } + + QueryBuilder distinctByIsFavourite() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'isFavourite'); + }); + } + + QueryBuilder + distinctByIsMnemonicVerified() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'isMnemonicVerified'); + }); + } + + QueryBuilder distinctByMainAddressType() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'mainAddressType'); + }); + } + + QueryBuilder distinctByName( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'name', caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByRestoreHeight() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'restoreHeight'); + }); + } + + QueryBuilder distinctByWalletId( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'walletId', caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByWalletType() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'walletType'); + }); + } +} + +extension WalletInfoQueryProperty + on QueryBuilder { + QueryBuilder idProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'id'); + }); + } + + QueryBuilder + cachedBalanceStringProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'cachedBalanceString'); + }); + } + + QueryBuilder cachedChainHeightProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'cachedChainHeight'); + }); + } + + QueryBuilder coinNameProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'coinName'); + }); + } + + QueryBuilder creationHeightProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'creationHeight'); + }); + } + + QueryBuilder + favouriteOrderIndexProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'favouriteOrderIndex'); + }); + } + + QueryBuilder isFavouriteProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'isFavourite'); + }); + } + + QueryBuilder + isMnemonicVerifiedProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'isMnemonicVerified'); + }); + } + + QueryBuilder + mainAddressTypeProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'mainAddressType'); + }); + } + + QueryBuilder nameProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'name'); + }); + } + + QueryBuilder restoreHeightProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'restoreHeight'); + }); + } + + QueryBuilder walletIdProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'walletId'); + }); + } + + QueryBuilder walletTypeProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'walletType'); + }); + } +} diff --git a/lib/wallets/models/tx_data.dart b/lib/wallets/models/tx_data.dart new file mode 100644 index 000000000..b95cd715b --- /dev/null +++ b/lib/wallets/models/tx_data.dart @@ -0,0 +1,106 @@ +import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart'; +import 'package:stackwallet/utilities/amount/amount.dart'; +import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; + +class TxData { + final FeeRateType? feeRateType; + final int? feeRateAmount; + final int? satsPerVByte; + + final Amount? fee; + final int? vSize; + + final String? raw; + + final String? txid; + final String? txHash; + + final String? note; + final String? noteOnChain; + + final List<({String address, Amount amount})>? recipients; + final Set? utxos; + + final String? changeAddress; + + final String? frostMSConfig; + + TxData({ + this.feeRateType, + this.feeRateAmount, + this.satsPerVByte, + this.fee, + this.vSize, + this.raw, + this.txid, + this.txHash, + this.note, + this.noteOnChain, + this.recipients, + this.utxos, + this.changeAddress, + this.frostMSConfig, + }); + + Amount? get amount => recipients != null && recipients!.isNotEmpty + ? recipients! + .map((e) => e.amount) + .reduce((total, amount) => total += amount) + : null; + + int? get estimatedSatsPerVByte => fee != null && vSize != null + ? (fee!.raw ~/ BigInt.from(vSize!)).toInt() + : null; + + TxData copyWith({ + FeeRateType? feeRateType, + int? feeRateAmount, + int? satsPerVByte, + Amount? fee, + int? vSize, + String? raw, + String? txid, + String? txHash, + String? note, + String? noteOnChain, + Set? utxos, + List<({String address, Amount amount})>? recipients, + String? frostMSConfig, + String? changeAddress, + }) { + return TxData( + feeRateType: feeRateType ?? this.feeRateType, + feeRateAmount: feeRateAmount ?? this.feeRateAmount, + satsPerVByte: satsPerVByte ?? this.satsPerVByte, + fee: fee ?? this.fee, + vSize: vSize ?? this.vSize, + raw: raw ?? this.raw, + txid: txid ?? this.txid, + txHash: txHash ?? this.txHash, + note: note ?? this.note, + noteOnChain: noteOnChain ?? this.noteOnChain, + utxos: utxos ?? this.utxos, + recipients: recipients ?? this.recipients, + frostMSConfig: frostMSConfig ?? this.frostMSConfig, + changeAddress: changeAddress ?? this.changeAddress, + ); + } + + @override + String toString() => 'TxData{' + 'feeRateType: $feeRateType, ' + 'feeRateAmount: $feeRateAmount, ' + 'satsPerVByte: $satsPerVByte, ' + 'fee: $fee, ' + 'vSize: $vSize, ' + 'raw: $raw, ' + 'txid: $txid, ' + 'txHash: $txHash, ' + 'note: $note, ' + 'noteOnChain: $noteOnChain, ' + 'recipients: $recipients, ' + 'utxos: $utxos, ' + 'frostMSConfig: $frostMSConfig, ' + 'changeAddress: $changeAddress' + '}'; +} diff --git a/lib/wallets/models/tx_recipient.dart b/lib/wallets/models/tx_recipient.dart new file mode 100644 index 000000000..92703caa8 --- /dev/null +++ b/lib/wallets/models/tx_recipient.dart @@ -0,0 +1,11 @@ +import 'package:stackwallet/utilities/amount/amount.dart'; + +class TxRecipient { + final String address; + final Amount amount; + + TxRecipient({ + required this.address, + required this.amount, + }); +} diff --git a/lib/wallets/wallet/bip39_hd_wallet.dart b/lib/wallets/wallet/bip39_hd_wallet.dart new file mode 100644 index 000000000..4991ef89c --- /dev/null +++ b/lib/wallets/wallet/bip39_hd_wallet.dart @@ -0,0 +1,152 @@ +import 'package:bip39/bip39.dart' as bip39; +import 'package:coinlib/coinlib.dart' as coinlib; +import 'package:isar/isar.dart'; +import 'package:stackwallet/exceptions/sw_exception.dart'; +import 'package:stackwallet/models/isar/models/isar_models.dart'; +import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; +import 'package:stackwallet/wallets/coin/bip39_hd_currency.dart'; +import 'package:stackwallet/wallets/models/tx_data.dart'; +import 'package:stackwallet/wallets/wallet/wallet.dart'; + +class Bip39HDWallet extends Wallet { + Bip39HDWallet(super.cryptoCurrency); + + /// Generates a receiving address of [walletInfo.mainAddressType]. If none + /// are in the current wallet db it will generate at index 0, otherwise the + /// highest index found in the current wallet db. + Future

generateNewReceivingAddress() async { + final current = await _currentReceivingAddress; + final index = current?.derivationIndex ?? 0; + const chain = 0; // receiving address + + final DerivePathType derivePathType; + switch (walletInfo.mainAddressType) { + case AddressType.p2pkh: + derivePathType = DerivePathType.bip44; + break; + + case AddressType.p2sh: + derivePathType = DerivePathType.bip44; + break; + + case AddressType.p2wpkh: + derivePathType = DerivePathType.bip44; + break; + + default: + throw Exception( + "Invalid AddressType accessed in $runtimeType generateNewReceivingAddress()", + ); + } + + final address = await _generateAddress( + chain: chain, + index: index, + derivePathType: derivePathType, + ); + + await mainDB.putAddress(address); + + return address; + } + + Future getMnemonic() async { + final mnemonic = await secureStorageInterface.read( + key: Wallet.mnemonicKey(walletId: walletInfo.walletId), + ); + + if (mnemonic == null) { + throw SWException("mnemonic has not been set"); + } + + return mnemonic; + } + + Future getMnemonicPassphrase() async { + final mnemonicPassphrase = await secureStorageInterface.read( + key: Wallet.mnemonicPassphraseKey(walletId: walletInfo.walletId), + ); + + if (mnemonicPassphrase == null) { + throw SWException("mnemonicPassphrase has not been set"); + } + + return mnemonicPassphrase; + } + + // ========== Private ======================================================== + + Future get _currentReceivingAddress async => + await mainDB.isar.addresses + .where() + .walletIdEqualTo(walletId) + .filter() + .typeEqualTo(walletInfo.mainAddressType) + .subTypeEqualTo(AddressSubType.receiving) + .sortByDerivationIndexDesc() + .findFirst(); + + Future _generateRootHDNode() async { + final seed = bip39.mnemonicToSeed( + await getMnemonic(), + passphrase: await getMnemonicPassphrase(), + ); + return coinlib.HDPrivateKey.fromSeed(seed); + } + + Future
_generateAddress({ + required int chain, + required int index, + required DerivePathType derivePathType, + }) async { + final root = await _generateRootHDNode(); + + final derivationPath = cryptoCurrency.constructDerivePath( + derivePathType: derivePathType, + chain: chain, + index: index, + ); + + final keys = root.derivePath(derivationPath); + + final data = cryptoCurrency.getAddressForPublicKey( + publicKey: keys.publicKey, + derivePathType: derivePathType, + ); + + final AddressSubType subType; + + if (chain == 0) { + subType = AddressSubType.receiving; + } else if (chain == 1) { + subType = AddressSubType.change; + } else { + // TODO others? + subType = AddressSubType.unknown; + } + + return Address( + walletId: walletId, + value: data.address.toString(), + publicKey: keys.publicKey.data, + derivationIndex: index, + derivationPath: DerivationPath()..value = derivationPath, + type: data.addressType, + subType: subType, + ); + } + + // ========== Overrides ====================================================== + + @override + Future confirmSend({required TxData txData}) { + // TODO: implement confirmSend + throw UnimplementedError(); + } + + @override + Future prepareSend({required TxData txData}) { + // TODO: implement prepareSend + throw UnimplementedError(); + } +} diff --git a/lib/wallets/wallet/cryptonote_wallet.dart b/lib/wallets/wallet/cryptonote_wallet.dart new file mode 100644 index 000000000..bff59cf9a --- /dev/null +++ b/lib/wallets/wallet/cryptonote_wallet.dart @@ -0,0 +1,33 @@ +import 'package:stackwallet/exceptions/sw_exception.dart'; +import 'package:stackwallet/wallets/models/tx_data.dart'; +import 'package:stackwallet/wallets/wallet/wallet.dart'; + +class CryptonoteWallet extends Wallet { + CryptonoteWallet(super.cryptoCurrency); + + Future getMnemonic() async { + final mnemonic = await secureStorageInterface.read( + key: Wallet.mnemonicKey(walletId: walletInfo.walletId), + ); + + if (mnemonic == null) { + throw SWException("mnemonic has not been set"); + } + + return mnemonic; + } + + // ========== Overrides ====================================================== + + @override + Future confirmSend({required TxData txData}) { + // TODO: implement confirmSend + throw UnimplementedError(); + } + + @override + Future prepareSend({required TxData txData}) { + // TODO: implement prepareSend + throw UnimplementedError(); + } +} diff --git a/lib/wallets/wallet/private_key_based_wallet.dart b/lib/wallets/wallet/private_key_based_wallet.dart new file mode 100644 index 000000000..ad3c3844c --- /dev/null +++ b/lib/wallets/wallet/private_key_based_wallet.dart @@ -0,0 +1,33 @@ +import 'package:stackwallet/exceptions/sw_exception.dart'; +import 'package:stackwallet/wallets/models/tx_data.dart'; +import 'package:stackwallet/wallets/wallet/wallet.dart'; + +class PrivateKeyBasedWallet extends Wallet { + PrivateKeyBasedWallet(super.cryptoCurrency); + + Future getPrivateKey() async { + final privateKey = await secureStorageInterface.read( + key: Wallet.privateKeyKey(walletId: walletInfo.walletId), + ); + + if (privateKey == null) { + throw SWException("privateKey has not been set"); + } + + return privateKey; + } + + // ========== Overrides ====================================================== + + @override + Future confirmSend({required TxData txData}) { + // TODO: implement confirmSend + throw UnimplementedError(); + } + + @override + Future prepareSend({required TxData txData}) { + // TODO: implement prepareSend + throw UnimplementedError(); + } +} diff --git a/lib/wallets/wallet/wallet.dart b/lib/wallets/wallet/wallet.dart new file mode 100644 index 000000000..8e85dc450 --- /dev/null +++ b/lib/wallets/wallet/wallet.dart @@ -0,0 +1,174 @@ +import 'package:isar/isar.dart'; +import 'package:stackwallet/db/isar/main_db.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; +import 'package:stackwallet/wallets/coin/bip39_hd_currency.dart'; +import 'package:stackwallet/wallets/coin/coins/bitcoin.dart'; +import 'package:stackwallet/wallets/coin/crypto_currency.dart'; +import 'package:stackwallet/wallets/isar_models/wallet_info.dart'; +import 'package:stackwallet/wallets/models/tx_data.dart'; +import 'package:stackwallet/wallets/wallet/bip39_hd_wallet.dart'; +import 'package:stackwallet/wallets/wallet/private_key_based_wallet.dart'; + +abstract class Wallet { + Wallet(this.cryptoCurrency); + + //============================================================================ + // ========== Properties ===================================================== + + final T cryptoCurrency; + + late final MainDB mainDB; + late final SecureStorageInterface secureStorageInterface; + late final WalletInfo walletInfo; + + //============================================================================ + // ========== Wallet Info Convenience Getters ================================ + + String get walletId => walletInfo.walletId; + WalletType get walletType => walletInfo.walletType; + + //============================================================================ + // ========== Static Main ==================================================== + + /// Create a new wallet and save [walletInfo] to db. + static Future create({ + required WalletInfo walletInfo, + required MainDB mainDB, + required SecureStorageInterface secureStorageInterface, + String? mnemonic, + String? mnemonicPassphrase, + String? privateKey, + int? startDate, + }) async { + final Wallet wallet = await _construct( + walletInfo: walletInfo, + mainDB: mainDB, + secureStorageInterface: secureStorageInterface, + ); + + switch (walletInfo.walletType) { + case WalletType.bip39: + await secureStorageInterface.write( + key: mnemonicKey(walletId: walletInfo.walletId), + value: mnemonic, + ); + await secureStorageInterface.write( + key: mnemonicPassphraseKey(walletId: walletInfo.walletId), + value: mnemonicPassphrase, + ); + break; + + case WalletType.cryptonote: + break; + + case WalletType.privateKeyBased: + break; + } + + // Store in db after wallet creation + await wallet.mainDB.isar.walletInfo.put(wallet.walletInfo); + + return wallet; + } + + /// Load an existing wallet via [WalletInfo] using [walletId]. + static Future load({ + required String walletId, + required MainDB mainDB, + required SecureStorageInterface secureStorageInterface, + }) async { + final walletInfo = await mainDB.isar.walletInfo + .where() + .walletIdEqualTo(walletId) + .findFirst(); + + if (walletInfo == null) { + throw Exception( + "WalletInfo not found for $walletId when trying to call Wallet.load()", + ); + } + + return await _construct( + walletInfo: walletInfo!, + mainDB: mainDB, + secureStorageInterface: secureStorageInterface, + ); + } + + //============================================================================ + // ========== Static Util ==================================================== + + static String mnemonicKey({ + required String walletId, + }) => + "${walletId}_mnemonic"; + + static String mnemonicPassphraseKey({ + required String walletId, + }) => + "${walletId}_mnemonicPassphrase"; + + static String privateKeyKey({ + required String walletId, + }) => + "${walletId}_privateKey"; + + //============================================================================ + // ========== Private ======================================================== + + /// Construct wallet instance by [WalletType] from [walletInfo] + static Future _construct({ + required WalletInfo walletInfo, + required MainDB mainDB, + required SecureStorageInterface secureStorageInterface, + }) async { + final Wallet wallet; + + final cryptoCurrency = _loadCurrency(walletInfo: walletInfo); + + switch (walletInfo.walletType) { + case WalletType.bip39: + wallet = Bip39HDWallet(cryptoCurrency as Bip39HDCurrency); + break; + + case WalletType.cryptonote: + wallet = PrivateKeyBasedWallet(cryptoCurrency); + break; + + case WalletType.privateKeyBased: + wallet = PrivateKeyBasedWallet(cryptoCurrency); + break; + } + + return wallet + ..secureStorageInterface = secureStorageInterface + ..mainDB = mainDB + ..walletInfo = walletInfo; + } + + static CryptoCurrency _loadCurrency({ + required WalletInfo walletInfo, + }) { + switch (walletInfo.coin) { + case Coin.bitcoin: + return Bitcoin(CryptoCurrencyNetwork.main); + case Coin.bitcoinTestNet: + return Bitcoin(CryptoCurrencyNetwork.test); + + default: + // should never hit in reality + throw Exception("Unknown cryupto currency"); + } + } + + //============================================================================ + // ========== Must override ================================================== + + /// Create and sign a transaction in preparation to submit to network + Future prepareSend({required TxData txData}); + + /// Broadcast transaction to network. On success update local wallet state to + /// reflect updated balance, transactions, utxos, etc. + Future confirmSend({required TxData txData}); +} diff --git a/lib/wallets/wallet_mixins/electrumx_mixin.dart b/lib/wallets/wallet_mixins/electrumx_mixin.dart new file mode 100644 index 000000000..44aa4e284 --- /dev/null +++ b/lib/wallets/wallet_mixins/electrumx_mixin.dart @@ -0,0 +1,3 @@ +mixin ElectrumXMixin { + // +} diff --git a/lib/wallets/wallets_service.dart b/lib/wallets/wallets_service.dart new file mode 100644 index 000000000..ad22480d3 --- /dev/null +++ b/lib/wallets/wallets_service.dart @@ -0,0 +1,15 @@ +import 'package:stackwallet/db/isar/main_db.dart'; +import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; + +class WalletsService { + late final SecureStorageInterface _secureStore; + late final MainDB _mainDB; + + WalletsService({ + required SecureStorageInterface secureStorageInterface, + required MainDB mainDB, + }) { + _secureStore = secureStorageInterface; + _mainDB = mainDB; + } +} diff --git a/pubspec.lock b/pubspec.lock index 167c41441..255b669d3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -254,6 +254,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.5.0" + coinlib: + dependency: "direct main" + description: + name: coinlib + sha256: c8018027801ddcb093837ad8f27e9ac014434b84860ecd3114ca28980614ec4a + url: "https://pub.dev" + source: hosted + version: "1.0.0-rc.3" collection: dependency: transitive description: @@ -1844,6 +1852,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.12+1" + wasm_interop: + dependency: transitive + description: + name: wasm_interop + sha256: b1b378f07a4cf0103c25faf34d9a64d2c3312135b9efb47e0ec116ec3b14e48f + url: "https://pub.dev" + source: hosted + version: "2.0.1" watcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f53d44348..0b6346054 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -144,6 +144,7 @@ dependencies: stellar_flutter_sdk: ^1.5.3 tezart: ^2.0.5 socks5_proxy: ^1.0.3+dev.3 + coinlib: ^1.0.0-rc.3 dev_dependencies: flutter_test: diff --git a/scripts/dev/build_runner.sh b/scripts/dev/build_runner.sh new file mode 100755 index 000000000..10c724c3e --- /dev/null +++ b/scripts/dev/build_runner.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +PROJECT_ROOT_DIR="$SCRIPT_DIR/../.." + +cd "$PROJECT_ROOT_DIR" || exit +dart run build_runner build --delete-conflicting-outputs diff --git a/test/services/coins/firo/firo_wallet_test.mocks.dart b/test/services/coins/firo/firo_wallet_test.mocks.dart index 0f7a0b0a3..adb59fb28 100644 --- a/test/services/coins/firo/firo_wallet_test.mocks.dart +++ b/test/services/coins/firo/firo_wallet_test.mocks.dart @@ -11,13 +11,14 @@ import 'package:mockito/mockito.dart' as _i1; import 'package:stackwallet/db/isar/main_db.dart' as _i9; import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart' as _i6; import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i3; -import 'package:stackwallet/models/isar/models/block_explorer.dart' as _i11; -import 'package:stackwallet/models/isar/models/contact_entry.dart' as _i10; -import 'package:stackwallet/models/isar/models/isar_models.dart' as _i12; +import 'package:stackwallet/models/isar/models/block_explorer.dart' as _i12; +import 'package:stackwallet/models/isar/models/contact_entry.dart' as _i11; +import 'package:stackwallet/models/isar/models/isar_models.dart' as _i13; import 'package:stackwallet/services/transaction_notification_tracker.dart' as _i8; import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i7; -import 'package:tuple/tuple.dart' as _i13; +import 'package:stackwallet/wallets/isar_models/wallet_info.dart' as _i10; +import 'package:tuple/tuple.dart' as _i14; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -635,13 +636,44 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValue: _i5.Future.value(false), ) as _i5.Future); @override - List<_i10.ContactEntry> getContactEntries() => (super.noSuchMethod( + _i5.Future putWalletInfo(_i10.WalletInfo? walletInfo) => + (super.noSuchMethod( + Invocation.method( + #putWalletInfo, + [walletInfo], + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); + @override + _i5.Future updateWalletInfo(_i10.WalletInfo? walletInfo) => + (super.noSuchMethod( + Invocation.method( + #updateWalletInfo, + [walletInfo], + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); + @override + _i5.Future deleteWallet({required String? walletId}) => + (super.noSuchMethod( + Invocation.method( + #deleteWallet, + [], + {#walletId: walletId}, + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); + @override + List<_i11.ContactEntry> getContactEntries() => (super.noSuchMethod( Invocation.method( #getContactEntries, [], ), - returnValue: <_i10.ContactEntry>[], - ) as List<_i10.ContactEntry>); + returnValue: <_i11.ContactEntry>[], + ) as List<_i11.ContactEntry>); @override _i5.Future deleteContactEntry({required String? id}) => (super.noSuchMethod( @@ -663,15 +695,15 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValue: _i5.Future.value(false), ) as _i5.Future); @override - _i10.ContactEntry? getContactEntry({required String? id}) => + _i11.ContactEntry? getContactEntry({required String? id}) => (super.noSuchMethod(Invocation.method( #getContactEntry, [], {#id: id}, - )) as _i10.ContactEntry?); + )) as _i11.ContactEntry?); @override _i5.Future putContactEntry( - {required _i10.ContactEntry? contactEntry}) => + {required _i11.ContactEntry? contactEntry}) => (super.noSuchMethod( Invocation.method( #putContactEntry, @@ -681,16 +713,16 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValue: _i5.Future.value(false), ) as _i5.Future); @override - _i11.TransactionBlockExplorer? getTransactionBlockExplorer( + _i12.TransactionBlockExplorer? getTransactionBlockExplorer( {required _i7.Coin? coin}) => (super.noSuchMethod(Invocation.method( #getTransactionBlockExplorer, [], {#coin: coin}, - )) as _i11.TransactionBlockExplorer?); + )) as _i12.TransactionBlockExplorer?); @override _i5.Future putTransactionBlockExplorer( - _i11.TransactionBlockExplorer? explorer) => + _i12.TransactionBlockExplorer? explorer) => (super.noSuchMethod( Invocation.method( #putTransactionBlockExplorer, @@ -699,13 +731,13 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValue: _i5.Future.value(0), ) as _i5.Future); @override - _i4.QueryBuilder<_i12.Address, _i12.Address, _i4.QAfterWhereClause> + _i4.QueryBuilder<_i13.Address, _i13.Address, _i4.QAfterWhereClause> getAddresses(String? walletId) => (super.noSuchMethod( Invocation.method( #getAddresses, [walletId], ), - returnValue: _FakeQueryBuilder_4<_i12.Address, _i12.Address, + returnValue: _FakeQueryBuilder_4<_i13.Address, _i13.Address, _i4.QAfterWhereClause>( this, Invocation.method( @@ -714,9 +746,9 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { ), ), ) as _i4 - .QueryBuilder<_i12.Address, _i12.Address, _i4.QAfterWhereClause>); + .QueryBuilder<_i13.Address, _i13.Address, _i4.QAfterWhereClause>); @override - _i5.Future putAddress(_i12.Address? address) => (super.noSuchMethod( + _i5.Future putAddress(_i13.Address? address) => (super.noSuchMethod( Invocation.method( #putAddress, [address], @@ -724,7 +756,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValue: _i5.Future.value(0), ) as _i5.Future); @override - _i5.Future> putAddresses(List<_i12.Address>? addresses) => + _i5.Future> putAddresses(List<_i13.Address>? addresses) => (super.noSuchMethod( Invocation.method( #putAddresses, @@ -733,7 +765,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValue: _i5.Future>.value([]), ) as _i5.Future>); @override - _i5.Future> updateOrPutAddresses(List<_i12.Address>? addresses) => + _i5.Future> updateOrPutAddresses(List<_i13.Address>? addresses) => (super.noSuchMethod( Invocation.method( #updateOrPutAddresses, @@ -742,7 +774,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValue: _i5.Future>.value([]), ) as _i5.Future>); @override - _i5.Future<_i12.Address?> getAddress( + _i5.Future<_i13.Address?> getAddress( String? walletId, String? address, ) => @@ -754,12 +786,12 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { address, ], ), - returnValue: _i5.Future<_i12.Address?>.value(), - ) as _i5.Future<_i12.Address?>); + returnValue: _i5.Future<_i13.Address?>.value(), + ) as _i5.Future<_i13.Address?>); @override _i5.Future updateAddress( - _i12.Address? oldAddress, - _i12.Address? newAddress, + _i13.Address? oldAddress, + _i13.Address? newAddress, ) => (super.noSuchMethod( Invocation.method( @@ -772,13 +804,13 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValue: _i5.Future.value(0), ) as _i5.Future); @override - _i4.QueryBuilder<_i12.Transaction, _i12.Transaction, _i4.QAfterWhereClause> + _i4.QueryBuilder<_i13.Transaction, _i13.Transaction, _i4.QAfterWhereClause> getTransactions(String? walletId) => (super.noSuchMethod( Invocation.method( #getTransactions, [walletId], ), - returnValue: _FakeQueryBuilder_4<_i12.Transaction, _i12.Transaction, + returnValue: _FakeQueryBuilder_4<_i13.Transaction, _i13.Transaction, _i4.QAfterWhereClause>( this, Invocation.method( @@ -786,10 +818,10 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { [walletId], ), ), - ) as _i4.QueryBuilder<_i12.Transaction, _i12.Transaction, + ) as _i4.QueryBuilder<_i13.Transaction, _i13.Transaction, _i4.QAfterWhereClause>); @override - _i5.Future putTransaction(_i12.Transaction? transaction) => + _i5.Future putTransaction(_i13.Transaction? transaction) => (super.noSuchMethod( Invocation.method( #putTransaction, @@ -798,7 +830,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValue: _i5.Future.value(0), ) as _i5.Future); @override - _i5.Future> putTransactions(List<_i12.Transaction>? transactions) => + _i5.Future> putTransactions(List<_i13.Transaction>? transactions) => (super.noSuchMethod( Invocation.method( #putTransactions, @@ -807,7 +839,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValue: _i5.Future>.value([]), ) as _i5.Future>); @override - _i5.Future<_i12.Transaction?> getTransaction( + _i5.Future<_i13.Transaction?> getTransaction( String? walletId, String? txid, ) => @@ -819,10 +851,10 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { txid, ], ), - returnValue: _i5.Future<_i12.Transaction?>.value(), - ) as _i5.Future<_i12.Transaction?>); + returnValue: _i5.Future<_i13.Transaction?>.value(), + ) as _i5.Future<_i13.Transaction?>); @override - _i5.Stream<_i12.Transaction?> watchTransaction({ + _i5.Stream<_i13.Transaction?> watchTransaction({ required int? id, bool? fireImmediately = false, }) => @@ -835,10 +867,10 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { #fireImmediately: fireImmediately, }, ), - returnValue: _i5.Stream<_i12.Transaction?>.empty(), - ) as _i5.Stream<_i12.Transaction?>); + returnValue: _i5.Stream<_i13.Transaction?>.empty(), + ) as _i5.Stream<_i13.Transaction?>); @override - _i4.QueryBuilder<_i12.UTXO, _i12.UTXO, _i4.QAfterWhereClause> getUTXOs( + _i4.QueryBuilder<_i13.UTXO, _i13.UTXO, _i4.QAfterWhereClause> getUTXOs( String? walletId) => (super.noSuchMethod( Invocation.method( @@ -846,16 +878,16 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { [walletId], ), returnValue: - _FakeQueryBuilder_4<_i12.UTXO, _i12.UTXO, _i4.QAfterWhereClause>( + _FakeQueryBuilder_4<_i13.UTXO, _i13.UTXO, _i4.QAfterWhereClause>( this, Invocation.method( #getUTXOs, [walletId], ), ), - ) as _i4.QueryBuilder<_i12.UTXO, _i12.UTXO, _i4.QAfterWhereClause>); + ) as _i4.QueryBuilder<_i13.UTXO, _i13.UTXO, _i4.QAfterWhereClause>); @override - _i5.Future putUTXO(_i12.UTXO? utxo) => (super.noSuchMethod( + _i5.Future putUTXO(_i13.UTXO? utxo) => (super.noSuchMethod( Invocation.method( #putUTXO, [utxo], @@ -864,7 +896,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValueForMissingStub: _i5.Future.value(), ) as _i5.Future); @override - _i5.Future putUTXOs(List<_i12.UTXO>? utxos) => (super.noSuchMethod( + _i5.Future putUTXOs(List<_i13.UTXO>? utxos) => (super.noSuchMethod( Invocation.method( #putUTXOs, [utxos], @@ -875,7 +907,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { @override _i5.Future updateUTXOs( String? walletId, - List<_i12.UTXO>? utxos, + List<_i13.UTXO>? utxos, ) => (super.noSuchMethod( Invocation.method( @@ -888,7 +920,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValue: _i5.Future.value(false), ) as _i5.Future); @override - _i5.Stream<_i12.UTXO?> watchUTXO({ + _i5.Stream<_i13.UTXO?> watchUTXO({ required int? id, bool? fireImmediately = false, }) => @@ -901,10 +933,10 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { #fireImmediately: fireImmediately, }, ), - returnValue: _i5.Stream<_i12.UTXO?>.empty(), - ) as _i5.Stream<_i12.UTXO?>); + returnValue: _i5.Stream<_i13.UTXO?>.empty(), + ) as _i5.Stream<_i13.UTXO?>); @override - _i4.QueryBuilder<_i12.TransactionNote, _i12.TransactionNote, + _i4.QueryBuilder<_i13.TransactionNote, _i13.TransactionNote, _i4.QAfterWhereClause> getTransactionNotes( String? walletId) => (super.noSuchMethod( @@ -912,18 +944,18 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { #getTransactionNotes, [walletId], ), - returnValue: _FakeQueryBuilder_4<_i12.TransactionNote, - _i12.TransactionNote, _i4.QAfterWhereClause>( + returnValue: _FakeQueryBuilder_4<_i13.TransactionNote, + _i13.TransactionNote, _i4.QAfterWhereClause>( this, Invocation.method( #getTransactionNotes, [walletId], ), ), - ) as _i4.QueryBuilder<_i12.TransactionNote, _i12.TransactionNote, + ) as _i4.QueryBuilder<_i13.TransactionNote, _i13.TransactionNote, _i4.QAfterWhereClause>); @override - _i5.Future putTransactionNote(_i12.TransactionNote? transactionNote) => + _i5.Future putTransactionNote(_i13.TransactionNote? transactionNote) => (super.noSuchMethod( Invocation.method( #putTransactionNote, @@ -934,7 +966,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { ) as _i5.Future); @override _i5.Future putTransactionNotes( - List<_i12.TransactionNote>? transactionNotes) => + List<_i13.TransactionNote>? transactionNotes) => (super.noSuchMethod( Invocation.method( #putTransactionNotes, @@ -944,7 +976,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValueForMissingStub: _i5.Future.value(), ) as _i5.Future); @override - _i5.Future<_i12.TransactionNote?> getTransactionNote( + _i5.Future<_i13.TransactionNote?> getTransactionNote( String? walletId, String? txid, ) => @@ -956,10 +988,10 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { txid, ], ), - returnValue: _i5.Future<_i12.TransactionNote?>.value(), - ) as _i5.Future<_i12.TransactionNote?>); + returnValue: _i5.Future<_i13.TransactionNote?>.value(), + ) as _i5.Future<_i13.TransactionNote?>); @override - _i5.Stream<_i12.TransactionNote?> watchTransactionNote({ + _i5.Stream<_i13.TransactionNote?> watchTransactionNote({ required int? id, bool? fireImmediately = false, }) => @@ -972,27 +1004,27 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { #fireImmediately: fireImmediately, }, ), - returnValue: _i5.Stream<_i12.TransactionNote?>.empty(), - ) as _i5.Stream<_i12.TransactionNote?>); + returnValue: _i5.Stream<_i13.TransactionNote?>.empty(), + ) as _i5.Stream<_i13.TransactionNote?>); @override - _i4.QueryBuilder<_i12.AddressLabel, _i12.AddressLabel, _i4.QAfterWhereClause> + _i4.QueryBuilder<_i13.AddressLabel, _i13.AddressLabel, _i4.QAfterWhereClause> getAddressLabels(String? walletId) => (super.noSuchMethod( Invocation.method( #getAddressLabels, [walletId], ), - returnValue: _FakeQueryBuilder_4<_i12.AddressLabel, - _i12.AddressLabel, _i4.QAfterWhereClause>( + returnValue: _FakeQueryBuilder_4<_i13.AddressLabel, + _i13.AddressLabel, _i4.QAfterWhereClause>( this, Invocation.method( #getAddressLabels, [walletId], ), ), - ) as _i4.QueryBuilder<_i12.AddressLabel, _i12.AddressLabel, + ) as _i4.QueryBuilder<_i13.AddressLabel, _i13.AddressLabel, _i4.QAfterWhereClause>); @override - _i5.Future putAddressLabel(_i12.AddressLabel? addressLabel) => + _i5.Future putAddressLabel(_i13.AddressLabel? addressLabel) => (super.noSuchMethod( Invocation.method( #putAddressLabel, @@ -1001,7 +1033,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValue: _i5.Future.value(0), ) as _i5.Future); @override - int putAddressLabelSync(_i12.AddressLabel? addressLabel) => + int putAddressLabelSync(_i13.AddressLabel? addressLabel) => (super.noSuchMethod( Invocation.method( #putAddressLabelSync, @@ -1010,7 +1042,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValue: 0, ) as int); @override - _i5.Future putAddressLabels(List<_i12.AddressLabel>? addressLabels) => + _i5.Future putAddressLabels(List<_i13.AddressLabel>? addressLabels) => (super.noSuchMethod( Invocation.method( #putAddressLabels, @@ -1020,7 +1052,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValueForMissingStub: _i5.Future.value(), ) as _i5.Future); @override - _i5.Future<_i12.AddressLabel?> getAddressLabel( + _i5.Future<_i13.AddressLabel?> getAddressLabel( String? walletId, String? addressString, ) => @@ -1032,10 +1064,10 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { addressString, ], ), - returnValue: _i5.Future<_i12.AddressLabel?>.value(), - ) as _i5.Future<_i12.AddressLabel?>); + returnValue: _i5.Future<_i13.AddressLabel?>.value(), + ) as _i5.Future<_i13.AddressLabel?>); @override - _i12.AddressLabel? getAddressLabelSync( + _i13.AddressLabel? getAddressLabelSync( String? walletId, String? addressString, ) => @@ -1045,9 +1077,9 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { walletId, addressString, ], - )) as _i12.AddressLabel?); + )) as _i13.AddressLabel?); @override - _i5.Stream<_i12.AddressLabel?> watchAddressLabel({ + _i5.Stream<_i13.AddressLabel?> watchAddressLabel({ required int? id, bool? fireImmediately = false, }) => @@ -1060,10 +1092,10 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { #fireImmediately: fireImmediately, }, ), - returnValue: _i5.Stream<_i12.AddressLabel?>.empty(), - ) as _i5.Stream<_i12.AddressLabel?>); + returnValue: _i5.Stream<_i13.AddressLabel?>.empty(), + ) as _i5.Stream<_i13.AddressLabel?>); @override - _i5.Future updateAddressLabel(_i12.AddressLabel? addressLabel) => + _i5.Future updateAddressLabel(_i13.AddressLabel? addressLabel) => (super.noSuchMethod( Invocation.method( #updateAddressLabel, @@ -1102,7 +1134,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { ) as _i5.Future); @override _i5.Future addNewTransactionData( - List<_i13.Tuple2<_i12.Transaction, _i12.Address?>>? transactionsData, + List<_i14.Tuple2<_i13.Transaction, _i13.Address?>>? transactionsData, String? walletId, ) => (super.noSuchMethod( @@ -1117,13 +1149,13 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValueForMissingStub: _i5.Future.value(), ) as _i5.Future); @override - _i4.QueryBuilder<_i12.EthContract, _i12.EthContract, _i4.QWhere> + _i4.QueryBuilder<_i13.EthContract, _i13.EthContract, _i4.QWhere> getEthContracts() => (super.noSuchMethod( Invocation.method( #getEthContracts, [], ), - returnValue: _FakeQueryBuilder_4<_i12.EthContract, _i12.EthContract, + returnValue: _FakeQueryBuilder_4<_i13.EthContract, _i13.EthContract, _i4.QWhere>( this, Invocation.method( @@ -1132,24 +1164,24 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { ), ), ) as _i4 - .QueryBuilder<_i12.EthContract, _i12.EthContract, _i4.QWhere>); + .QueryBuilder<_i13.EthContract, _i13.EthContract, _i4.QWhere>); @override - _i5.Future<_i12.EthContract?> getEthContract(String? contractAddress) => + _i5.Future<_i13.EthContract?> getEthContract(String? contractAddress) => (super.noSuchMethod( Invocation.method( #getEthContract, [contractAddress], ), - returnValue: _i5.Future<_i12.EthContract?>.value(), - ) as _i5.Future<_i12.EthContract?>); + returnValue: _i5.Future<_i13.EthContract?>.value(), + ) as _i5.Future<_i13.EthContract?>); @override - _i12.EthContract? getEthContractSync(String? contractAddress) => + _i13.EthContract? getEthContractSync(String? contractAddress) => (super.noSuchMethod(Invocation.method( #getEthContractSync, [contractAddress], - )) as _i12.EthContract?); + )) as _i13.EthContract?); @override - _i5.Future putEthContract(_i12.EthContract? contract) => + _i5.Future putEthContract(_i13.EthContract? contract) => (super.noSuchMethod( Invocation.method( #putEthContract, @@ -1158,7 +1190,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB { returnValue: _i5.Future.value(0), ) as _i5.Future); @override - _i5.Future putEthContracts(List<_i12.EthContract>? contracts) => + _i5.Future putEthContracts(List<_i13.EthContract>? contracts) => (super.noSuchMethod( Invocation.method( #putEthContracts, diff --git a/test/widget_tests/transaction_card_test.mocks.dart b/test/widget_tests/transaction_card_test.mocks.dart index 5ef7ef5a1..225f23d93 100644 --- a/test/widget_tests/transaction_card_test.mocks.dart +++ b/test/widget_tests/transaction_card_test.mocks.dart @@ -16,8 +16,8 @@ import 'package:stackwallet/db/isar/main_db.dart' as _i14; import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart' as _i13; import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i12; import 'package:stackwallet/models/balance.dart' as _i9; -import 'package:stackwallet/models/isar/models/block_explorer.dart' as _i37; -import 'package:stackwallet/models/isar/models/contact_entry.dart' as _i36; +import 'package:stackwallet/models/isar/models/block_explorer.dart' as _i38; +import 'package:stackwallet/models/isar/models/contact_entry.dart' as _i37; import 'package:stackwallet/models/isar/models/isar_models.dart' as _i23; import 'package:stackwallet/models/isar/stack_theme.dart' as _i34; import 'package:stackwallet/models/models.dart' as _i8; @@ -41,6 +41,7 @@ import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i28; import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i19; import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i27; import 'package:stackwallet/utilities/prefs.dart' as _i21; +import 'package:stackwallet/wallets/isar_models/wallet_info.dart' as _i36; import 'package:tuple/tuple.dart' as _i15; // ignore_for_file: type=lint @@ -3044,13 +3045,44 @@ class MockMainDB extends _i1.Mock implements _i14.MainDB { returnValue: _i20.Future.value(false), ) as _i20.Future); @override - List<_i36.ContactEntry> getContactEntries() => (super.noSuchMethod( + _i20.Future putWalletInfo(_i36.WalletInfo? walletInfo) => + (super.noSuchMethod( + Invocation.method( + #putWalletInfo, + [walletInfo], + ), + returnValue: _i20.Future.value(), + returnValueForMissingStub: _i20.Future.value(), + ) as _i20.Future); + @override + _i20.Future updateWalletInfo(_i36.WalletInfo? walletInfo) => + (super.noSuchMethod( + Invocation.method( + #updateWalletInfo, + [walletInfo], + ), + returnValue: _i20.Future.value(), + returnValueForMissingStub: _i20.Future.value(), + ) as _i20.Future); + @override + _i20.Future deleteWallet({required String? walletId}) => + (super.noSuchMethod( + Invocation.method( + #deleteWallet, + [], + {#walletId: walletId}, + ), + returnValue: _i20.Future.value(), + returnValueForMissingStub: _i20.Future.value(), + ) as _i20.Future); + @override + List<_i37.ContactEntry> getContactEntries() => (super.noSuchMethod( Invocation.method( #getContactEntries, [], ), - returnValue: <_i36.ContactEntry>[], - ) as List<_i36.ContactEntry>); + returnValue: <_i37.ContactEntry>[], + ) as List<_i37.ContactEntry>); @override _i20.Future deleteContactEntry({required String? id}) => (super.noSuchMethod( @@ -3072,15 +3104,15 @@ class MockMainDB extends _i1.Mock implements _i14.MainDB { returnValue: _i20.Future.value(false), ) as _i20.Future); @override - _i36.ContactEntry? getContactEntry({required String? id}) => + _i37.ContactEntry? getContactEntry({required String? id}) => (super.noSuchMethod(Invocation.method( #getContactEntry, [], {#id: id}, - )) as _i36.ContactEntry?); + )) as _i37.ContactEntry?); @override _i20.Future putContactEntry( - {required _i36.ContactEntry? contactEntry}) => + {required _i37.ContactEntry? contactEntry}) => (super.noSuchMethod( Invocation.method( #putContactEntry, @@ -3090,16 +3122,16 @@ class MockMainDB extends _i1.Mock implements _i14.MainDB { returnValue: _i20.Future.value(false), ) as _i20.Future); @override - _i37.TransactionBlockExplorer? getTransactionBlockExplorer( + _i38.TransactionBlockExplorer? getTransactionBlockExplorer( {required _i19.Coin? coin}) => (super.noSuchMethod(Invocation.method( #getTransactionBlockExplorer, [], {#coin: coin}, - )) as _i37.TransactionBlockExplorer?); + )) as _i38.TransactionBlockExplorer?); @override _i20.Future putTransactionBlockExplorer( - _i37.TransactionBlockExplorer? explorer) => + _i38.TransactionBlockExplorer? explorer) => (super.noSuchMethod( Invocation.method( #putTransactionBlockExplorer,