WIP restructure w/moving from hive to isar for wallets and using coinlib

This commit is contained in:
julian 2023-09-14 17:34:01 -06:00
parent 5ac7ae95cb
commit adfe3e181e
22 changed files with 2994 additions and 104 deletions

View file

@ -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<void> putWalletInfo(WalletInfo walletInfo) async {
try {
await isar.writeTxn(() async {
await isar.walletInfo.put(walletInfo);
});
} catch (e) {
throw MainDBException("failed putWalletInfo()", e);
}
}
Future<void> 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<void> deleteWallet({required String walletId}) async {
//
}
// contact entries
List<ContactEntry> getContactEntries() {
return isar.contactEntrys.where().sortByName().findAllSync();

View file

@ -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(),

View file

@ -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<String, dynamic> 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,
});
}

View file

@ -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,
});
}

View file

@ -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",
);
}

View file

@ -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");
}
}
}

View file

@ -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);
}

View file

@ -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<String, dynamic> 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<String, String> 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;
}

File diff suppressed because it is too large Load diff

View file

@ -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<UTXO>? 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<UTXO>? 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'
'}';
}

View file

@ -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,
});
}

View file

@ -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<T extends Bip39HDCurrency> extends Wallet<T> {
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<Address> 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<String> 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<String> 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<Address?> get _currentReceivingAddress async =>
await mainDB.isar.addresses
.where()
.walletIdEqualTo(walletId)
.filter()
.typeEqualTo(walletInfo.mainAddressType)
.subTypeEqualTo(AddressSubType.receiving)
.sortByDerivationIndexDesc()
.findFirst();
Future<coinlib.HDPrivateKey> _generateRootHDNode() async {
final seed = bip39.mnemonicToSeed(
await getMnemonic(),
passphrase: await getMnemonicPassphrase(),
);
return coinlib.HDPrivateKey.fromSeed(seed);
}
Future<Address> _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<TxData> confirmSend({required TxData txData}) {
// TODO: implement confirmSend
throw UnimplementedError();
}
@override
Future<TxData> prepareSend({required TxData txData}) {
// TODO: implement prepareSend
throw UnimplementedError();
}
}

View file

@ -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<String> 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<TxData> confirmSend({required TxData txData}) {
// TODO: implement confirmSend
throw UnimplementedError();
}
@override
Future<TxData> prepareSend({required TxData txData}) {
// TODO: implement prepareSend
throw UnimplementedError();
}
}

View file

@ -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<String> 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<TxData> confirmSend({required TxData txData}) {
// TODO: implement confirmSend
throw UnimplementedError();
}
@override
Future<TxData> prepareSend({required TxData txData}) {
// TODO: implement prepareSend
throw UnimplementedError();
}
}

View file

@ -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<T extends CryptoCurrency> {
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<Wallet> 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<Wallet> 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<Wallet> _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<TxData> prepareSend({required TxData txData});
/// Broadcast transaction to network. On success update local wallet state to
/// reflect updated balance, transactions, utxos, etc.
Future<TxData> confirmSend({required TxData txData});
}

View file

@ -0,0 +1,3 @@
mixin ElectrumXMixin {
//
}

View file

@ -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;
}
}

View file

@ -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:

View file

@ -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:

8
scripts/dev/build_runner.sh Executable file
View file

@ -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

View file

@ -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<bool>.value(false),
) as _i5.Future<bool>);
@override
List<_i10.ContactEntry> getContactEntries() => (super.noSuchMethod(
_i5.Future<void> putWalletInfo(_i10.WalletInfo? walletInfo) =>
(super.noSuchMethod(
Invocation.method(
#putWalletInfo,
[walletInfo],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<void> updateWalletInfo(_i10.WalletInfo? walletInfo) =>
(super.noSuchMethod(
Invocation.method(
#updateWalletInfo,
[walletInfo],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<void> deleteWallet({required String? walletId}) =>
(super.noSuchMethod(
Invocation.method(
#deleteWallet,
[],
{#walletId: walletId},
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@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<bool> deleteContactEntry({required String? id}) =>
(super.noSuchMethod(
@ -663,15 +695,15 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB {
returnValue: _i5.Future<bool>.value(false),
) as _i5.Future<bool>);
@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<bool> 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<bool>.value(false),
) as _i5.Future<bool>);
@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<int> 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<int>.value(0),
) as _i5.Future<int>);
@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<int> putAddress(_i12.Address? address) => (super.noSuchMethod(
_i5.Future<int> 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<int>.value(0),
) as _i5.Future<int>);
@override
_i5.Future<List<int>> putAddresses(List<_i12.Address>? addresses) =>
_i5.Future<List<int>> 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<List<int>>.value(<int>[]),
) as _i5.Future<List<int>>);
@override
_i5.Future<List<int>> updateOrPutAddresses(List<_i12.Address>? addresses) =>
_i5.Future<List<int>> 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<List<int>>.value(<int>[]),
) as _i5.Future<List<int>>);
@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<int> 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<int>.value(0),
) as _i5.Future<int>);
@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<int> putTransaction(_i12.Transaction? transaction) =>
_i5.Future<int> putTransaction(_i13.Transaction? transaction) =>
(super.noSuchMethod(
Invocation.method(
#putTransaction,
@ -798,7 +830,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB {
returnValue: _i5.Future<int>.value(0),
) as _i5.Future<int>);
@override
_i5.Future<List<int>> putTransactions(List<_i12.Transaction>? transactions) =>
_i5.Future<List<int>> 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<List<int>>.value(<int>[]),
) as _i5.Future<List<int>>);
@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<void> putUTXO(_i12.UTXO? utxo) => (super.noSuchMethod(
_i5.Future<void> 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<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<void> putUTXOs(List<_i12.UTXO>? utxos) => (super.noSuchMethod(
_i5.Future<void> 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<bool> 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<bool>.value(false),
) as _i5.Future<bool>);
@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<void> putTransactionNote(_i12.TransactionNote? transactionNote) =>
_i5.Future<void> putTransactionNote(_i13.TransactionNote? transactionNote) =>
(super.noSuchMethod(
Invocation.method(
#putTransactionNote,
@ -934,7 +966,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB {
) as _i5.Future<void>);
@override
_i5.Future<void> 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<void>.value(),
) as _i5.Future<void>);
@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<int> putAddressLabel(_i12.AddressLabel? addressLabel) =>
_i5.Future<int> putAddressLabel(_i13.AddressLabel? addressLabel) =>
(super.noSuchMethod(
Invocation.method(
#putAddressLabel,
@ -1001,7 +1033,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB {
returnValue: _i5.Future<int>.value(0),
) as _i5.Future<int>);
@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<void> putAddressLabels(List<_i12.AddressLabel>? addressLabels) =>
_i5.Future<void> 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<void>.value(),
) as _i5.Future<void>);
@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<int> updateAddressLabel(_i12.AddressLabel? addressLabel) =>
_i5.Future<int> updateAddressLabel(_i13.AddressLabel? addressLabel) =>
(super.noSuchMethod(
Invocation.method(
#updateAddressLabel,
@ -1102,7 +1134,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB {
) as _i5.Future<void>);
@override
_i5.Future<void> 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<void>.value(),
) as _i5.Future<void>);
@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<int> putEthContract(_i12.EthContract? contract) =>
_i5.Future<int> putEthContract(_i13.EthContract? contract) =>
(super.noSuchMethod(
Invocation.method(
#putEthContract,
@ -1158,7 +1190,7 @@ class MockMainDB extends _i1.Mock implements _i9.MainDB {
returnValue: _i5.Future<int>.value(0),
) as _i5.Future<int>);
@override
_i5.Future<void> putEthContracts(List<_i12.EthContract>? contracts) =>
_i5.Future<void> putEthContracts(List<_i13.EthContract>? contracts) =>
(super.noSuchMethod(
Invocation.method(
#putEthContracts,

View file

@ -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<bool>.value(false),
) as _i20.Future<bool>);
@override
List<_i36.ContactEntry> getContactEntries() => (super.noSuchMethod(
_i20.Future<void> putWalletInfo(_i36.WalletInfo? walletInfo) =>
(super.noSuchMethod(
Invocation.method(
#putWalletInfo,
[walletInfo],
),
returnValue: _i20.Future<void>.value(),
returnValueForMissingStub: _i20.Future<void>.value(),
) as _i20.Future<void>);
@override
_i20.Future<void> updateWalletInfo(_i36.WalletInfo? walletInfo) =>
(super.noSuchMethod(
Invocation.method(
#updateWalletInfo,
[walletInfo],
),
returnValue: _i20.Future<void>.value(),
returnValueForMissingStub: _i20.Future<void>.value(),
) as _i20.Future<void>);
@override
_i20.Future<void> deleteWallet({required String? walletId}) =>
(super.noSuchMethod(
Invocation.method(
#deleteWallet,
[],
{#walletId: walletId},
),
returnValue: _i20.Future<void>.value(),
returnValueForMissingStub: _i20.Future<void>.value(),
) as _i20.Future<void>);
@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<bool> deleteContactEntry({required String? id}) =>
(super.noSuchMethod(
@ -3072,15 +3104,15 @@ class MockMainDB extends _i1.Mock implements _i14.MainDB {
returnValue: _i20.Future<bool>.value(false),
) as _i20.Future<bool>);
@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<bool> 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<bool>.value(false),
) as _i20.Future<bool>);
@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<int> putTransactionBlockExplorer(
_i37.TransactionBlockExplorer? explorer) =>
_i38.TransactionBlockExplorer? explorer) =>
(super.noSuchMethod(
Invocation.method(
#putTransactionBlockExplorer,