mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-17 01:37:54 +00:00
WIP bitcoin frost wallet addition
This commit is contained in:
parent
755cc049b0
commit
85b66fd849
26 changed files with 1492 additions and 61 deletions
|
@ -163,6 +163,7 @@ enum AddressType {
|
||||||
spark,
|
spark,
|
||||||
stellar,
|
stellar,
|
||||||
tezos,
|
tezos,
|
||||||
|
frostMS,
|
||||||
;
|
;
|
||||||
|
|
||||||
String get readableName {
|
String get readableName {
|
||||||
|
@ -193,6 +194,8 @@ enum AddressType {
|
||||||
return "Stellar";
|
return "Stellar";
|
||||||
case AddressType.tezos:
|
case AddressType.tezos:
|
||||||
return "Tezos";
|
return "Tezos";
|
||||||
|
case AddressType.frostMS:
|
||||||
|
return "FrostMS";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,6 +266,7 @@ const _AddresstypeEnumValueMap = {
|
||||||
'spark': 10,
|
'spark': 10,
|
||||||
'stellar': 11,
|
'stellar': 11,
|
||||||
'tezos': 12,
|
'tezos': 12,
|
||||||
|
'frostMS': 13,
|
||||||
};
|
};
|
||||||
const _AddresstypeValueEnumMap = {
|
const _AddresstypeValueEnumMap = {
|
||||||
0: AddressType.p2pkh,
|
0: AddressType.p2pkh,
|
||||||
|
@ -281,6 +282,7 @@ const _AddresstypeValueEnumMap = {
|
||||||
10: AddressType.spark,
|
10: AddressType.spark,
|
||||||
11: AddressType.stellar,
|
11: AddressType.stellar,
|
||||||
12: AddressType.tezos,
|
12: AddressType.tezos,
|
||||||
|
13: AddressType.frostMS,
|
||||||
};
|
};
|
||||||
|
|
||||||
Id _addressGetId(Address object) {
|
Id _addressGetId(Address object) {
|
||||||
|
|
|
@ -26,6 +26,7 @@ import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
import 'package:stackwallet/wallets/isar/providers/eth/current_token_wallet_provider.dart';
|
import 'package:stackwallet/wallets/isar/providers/eth/current_token_wallet_provider.dart';
|
||||||
import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart';
|
import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart';
|
import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart';
|
||||||
|
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart';
|
||||||
import 'package:stackwallet/widgets/animated_text.dart';
|
import 'package:stackwallet/widgets/animated_text.dart';
|
||||||
|
|
||||||
final feeSheetSessionCacheProvider =
|
final feeSheetSessionCacheProvider =
|
||||||
|
@ -697,7 +698,7 @@ class _TransactionFeeSelectionSheetState
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
if (coin.isElectrumXCoin)
|
if (wallet is ElectrumXInterface)
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final state =
|
final state =
|
||||||
|
@ -766,7 +767,7 @@ class _TransactionFeeSelectionSheetState
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (coin.isElectrumXCoin)
|
if (wallet is ElectrumXInterface)
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
|
|
|
@ -166,6 +166,8 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
|
||||||
case Coin.firo:
|
case Coin.firo:
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
case Coin.bitcoincashTestnet:
|
case Coin.bitcoincashTestnet:
|
||||||
|
@ -757,6 +759,8 @@ class _NodeFormState extends ConsumerState<NodeForm> {
|
||||||
case Coin.eCash:
|
case Coin.eCash:
|
||||||
case Coin.stellar:
|
case Coin.stellar:
|
||||||
case Coin.stellarTestnet:
|
case Coin.stellarTestnet:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case Coin.ethereum:
|
case Coin.ethereum:
|
||||||
|
|
|
@ -148,6 +148,8 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
case Coin.bitcoincashTestnet:
|
case Coin.bitcoincashTestnet:
|
||||||
case Coin.eCash:
|
case Coin.eCash:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
final client = ElectrumXClient(
|
final client = ElectrumXClient(
|
||||||
host: node!.host,
|
host: node!.host,
|
||||||
port: node.port,
|
port: node.port,
|
||||||
|
|
|
@ -52,6 +52,7 @@ import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart';
|
||||||
import 'package:stackwallet/wallets/models/tx_data.dart';
|
import 'package:stackwallet/wallets/models/tx_data.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart';
|
import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart';
|
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart';
|
||||||
|
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart';
|
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart';
|
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart';
|
||||||
import 'package:stackwallet/widgets/animated_text.dart';
|
import 'package:stackwallet/widgets/animated_text.dart';
|
||||||
|
@ -1566,7 +1567,8 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
||||||
if (!([Coin.nano, Coin.banano, Coin.epicCash, Coin.tezos]
|
if (!([Coin.nano, Coin.banano, Coin.epicCash, Coin.tezos]
|
||||||
.contains(coin)))
|
.contains(coin)))
|
||||||
ConditionalParent(
|
ConditionalParent(
|
||||||
condition: coin.isElectrumXCoin &&
|
condition: ref.watch(pWallets).getWallet(walletId)
|
||||||
|
is ElectrumXInterface &&
|
||||||
!(((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
!(((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
||||||
(ref.watch(publicPrivateBalanceStateProvider.state).state ==
|
(ref.watch(publicPrivateBalanceStateProvider.state).state ==
|
||||||
FiroType.lelantus ||
|
FiroType.lelantus ||
|
||||||
|
|
|
@ -24,6 +24,7 @@ import 'package:stackwallet/services/wallets.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
import 'package:stackwallet/utilities/prefs.dart';
|
import 'package:stackwallet/utilities/prefs.dart';
|
||||||
|
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart';
|
||||||
|
|
||||||
import 'exchange/exchange.dart';
|
import 'exchange/exchange.dart';
|
||||||
|
|
||||||
|
@ -123,7 +124,7 @@ class NotificationsService extends ChangeNotifier {
|
||||||
|
|
||||||
final node = nodeService.getPrimaryNodeFor(coin: coin);
|
final node = nodeService.getPrimaryNodeFor(coin: coin);
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
if (coin.isElectrumXCoin) {
|
if (wallet is ElectrumXInterface) {
|
||||||
final eNode = ElectrumXNode(
|
final eNode = ElectrumXNode(
|
||||||
address: node.host,
|
address: node.host,
|
||||||
port: node.port,
|
port: node.port,
|
||||||
|
|
|
@ -37,6 +37,8 @@ class CoinThemeColorDefault {
|
||||||
switch (coin) {
|
switch (coin) {
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
return bitcoin;
|
return bitcoin;
|
||||||
case Coin.litecoin:
|
case Coin.litecoin:
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
|
|
|
@ -1680,6 +1680,8 @@ class StackColors extends ThemeExtension<StackColors> {
|
||||||
switch (coin) {
|
switch (coin) {
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
return _coin.bitcoin;
|
return _coin.bitcoin;
|
||||||
case Coin.litecoin:
|
case Coin.litecoin:
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
|
|
|
@ -40,6 +40,8 @@ enum AmountUnit {
|
||||||
case Coin.litecoin:
|
case Coin.litecoin:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
case Coin.bitcoincashTestnet:
|
case Coin.bitcoincashTestnet:
|
||||||
|
|
|
@ -18,6 +18,7 @@ Uri getDefaultBlockExplorerUrlFor({
|
||||||
required String txid,
|
required String txid,
|
||||||
}) {
|
}) {
|
||||||
switch (coin) {
|
switch (coin) {
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
return Uri.parse("https://mempool.space/tx/$txid");
|
return Uri.parse("https://mempool.space/tx/$txid");
|
||||||
case Coin.litecoin:
|
case Coin.litecoin:
|
||||||
|
@ -25,6 +26,7 @@ Uri getDefaultBlockExplorerUrlFor({
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
return Uri.parse("https://chain.so/tx/LTCTEST/$txid");
|
return Uri.parse("https://chain.so/tx/LTCTEST/$txid");
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
return Uri.parse("https://mempool.space/testnet/tx/$txid");
|
return Uri.parse("https://mempool.space/testnet/tx/$txid");
|
||||||
case Coin.dogecoin:
|
case Coin.dogecoin:
|
||||||
return Uri.parse("https://chain.so/tx/DOGE/$txid");
|
return Uri.parse("https://chain.so/tx/DOGE/$txid");
|
||||||
|
|
|
@ -69,6 +69,7 @@ abstract class Constants {
|
||||||
static BigInt satsPerCoin(Coin coin) {
|
static BigInt satsPerCoin(Coin coin) {
|
||||||
switch (coin) {
|
switch (coin) {
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
case Coin.litecoin:
|
case Coin.litecoin:
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
|
@ -76,6 +77,7 @@ abstract class Constants {
|
||||||
case Coin.dogecoin:
|
case Coin.dogecoin:
|
||||||
case Coin.firo:
|
case Coin.firo:
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
case Coin.dogecoinTestNet:
|
case Coin.dogecoinTestNet:
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
case Coin.epicCash:
|
case Coin.epicCash:
|
||||||
|
@ -113,6 +115,7 @@ abstract class Constants {
|
||||||
static int decimalPlacesForCoin(Coin coin) {
|
static int decimalPlacesForCoin(Coin coin) {
|
||||||
switch (coin) {
|
switch (coin) {
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
case Coin.litecoin:
|
case Coin.litecoin:
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
|
@ -120,6 +123,7 @@ abstract class Constants {
|
||||||
case Coin.dogecoin:
|
case Coin.dogecoin:
|
||||||
case Coin.firo:
|
case Coin.firo:
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
case Coin.dogecoinTestNet:
|
case Coin.dogecoinTestNet:
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
case Coin.epicCash:
|
case Coin.epicCash:
|
||||||
|
@ -189,6 +193,10 @@ abstract class Constants {
|
||||||
case Coin.wownero:
|
case Coin.wownero:
|
||||||
values.addAll([14, 25]);
|
values.addAll([14, 25]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
|
throw ArgumentError("Frost mnemonic lengths unsupported");
|
||||||
}
|
}
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
@ -198,6 +206,8 @@ abstract class Constants {
|
||||||
switch (coin) {
|
switch (coin) {
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
case Coin.bitcoincashTestnet:
|
case Coin.bitcoincashTestnet:
|
||||||
case Coin.eCash:
|
case Coin.eCash:
|
||||||
|
@ -277,6 +287,10 @@ abstract class Constants {
|
||||||
|
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
return 25;
|
return 25;
|
||||||
|
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
|
throw ArgumentError("Frost mnemonic length unsupported");
|
||||||
//
|
//
|
||||||
// default:
|
// default:
|
||||||
// -1;
|
// -1;
|
||||||
|
|
|
@ -312,6 +312,7 @@ abstract class DefaultNodes {
|
||||||
static NodeModel getNodeFor(Coin coin) {
|
static NodeModel getNodeFor(Coin coin) {
|
||||||
switch (coin) {
|
switch (coin) {
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
return bitcoin;
|
return bitcoin;
|
||||||
|
|
||||||
case Coin.litecoin:
|
case Coin.litecoin:
|
||||||
|
@ -360,6 +361,7 @@ abstract class DefaultNodes {
|
||||||
return tezos;
|
return tezos;
|
||||||
|
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
return bitcoinTestnet;
|
return bitcoinTestnet;
|
||||||
|
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
|
|
|
@ -13,6 +13,7 @@ import 'package:stackwallet/utilities/constants.dart';
|
||||||
|
|
||||||
enum Coin {
|
enum Coin {
|
||||||
bitcoin,
|
bitcoin,
|
||||||
|
bitcoinFrost,
|
||||||
monero,
|
monero,
|
||||||
banano,
|
banano,
|
||||||
bitcoincash,
|
bitcoincash,
|
||||||
|
@ -35,6 +36,7 @@ enum Coin {
|
||||||
///
|
///
|
||||||
|
|
||||||
bitcoinTestNet,
|
bitcoinTestNet,
|
||||||
|
bitcoinFrostTestNet,
|
||||||
bitcoincashTestnet,
|
bitcoincashTestnet,
|
||||||
dogecoinTestNet,
|
dogecoinTestNet,
|
||||||
firoTestNet,
|
firoTestNet,
|
||||||
|
@ -47,6 +49,8 @@ extension CoinExt on Coin {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
return "Bitcoin";
|
return "Bitcoin";
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
return "Bitcoin Frost";
|
||||||
case Coin.litecoin:
|
case Coin.litecoin:
|
||||||
return "Litecoin";
|
return "Litecoin";
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
|
@ -79,6 +83,8 @@ extension CoinExt on Coin {
|
||||||
return "Banano";
|
return "Banano";
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
return "tBitcoin";
|
return "tBitcoin";
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
|
return "tBitcoin Frost";
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
return "tLitecoin";
|
return "tLitecoin";
|
||||||
case Coin.bitcoincashTestnet:
|
case Coin.bitcoincashTestnet:
|
||||||
|
@ -95,6 +101,7 @@ extension CoinExt on Coin {
|
||||||
String get ticker {
|
String get ticker {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
return "BTC";
|
return "BTC";
|
||||||
case Coin.litecoin:
|
case Coin.litecoin:
|
||||||
return "LTC";
|
return "LTC";
|
||||||
|
@ -127,6 +134,7 @@ extension CoinExt on Coin {
|
||||||
case Coin.banano:
|
case Coin.banano:
|
||||||
return "BAN";
|
return "BAN";
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
return "tBTC";
|
return "tBTC";
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
return "tLTC";
|
return "tLTC";
|
||||||
|
@ -144,6 +152,7 @@ extension CoinExt on Coin {
|
||||||
String get uriScheme {
|
String get uriScheme {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
return "bitcoin";
|
return "bitcoin";
|
||||||
case Coin.litecoin:
|
case Coin.litecoin:
|
||||||
return "litecoin";
|
return "litecoin";
|
||||||
|
@ -177,6 +186,7 @@ extension CoinExt on Coin {
|
||||||
case Coin.banano:
|
case Coin.banano:
|
||||||
return "ban";
|
return "ban";
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
return "bitcoin";
|
return "bitcoin";
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
return "litecoin";
|
return "litecoin";
|
||||||
|
@ -191,36 +201,6 @@ extension CoinExt on Coin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get isElectrumXCoin {
|
|
||||||
switch (this) {
|
|
||||||
case Coin.bitcoin:
|
|
||||||
case Coin.litecoin:
|
|
||||||
case Coin.bitcoincash:
|
|
||||||
case Coin.dogecoin:
|
|
||||||
case Coin.firo:
|
|
||||||
case Coin.namecoin:
|
|
||||||
case Coin.particl:
|
|
||||||
case Coin.bitcoinTestNet:
|
|
||||||
case Coin.litecoinTestNet:
|
|
||||||
case Coin.bitcoincashTestnet:
|
|
||||||
case Coin.firoTestNet:
|
|
||||||
case Coin.dogecoinTestNet:
|
|
||||||
case Coin.eCash:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case Coin.epicCash:
|
|
||||||
case Coin.ethereum:
|
|
||||||
case Coin.monero:
|
|
||||||
case Coin.tezos:
|
|
||||||
case Coin.wownero:
|
|
||||||
case Coin.nano:
|
|
||||||
case Coin.banano:
|
|
||||||
case Coin.stellar:
|
|
||||||
case Coin.stellarTestnet:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get hasMnemonicPassphraseSupport {
|
bool get hasMnemonicPassphraseSupport {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
|
@ -241,6 +221,8 @@ extension CoinExt on Coin {
|
||||||
case Coin.stellarTestnet:
|
case Coin.stellarTestnet:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
case Coin.epicCash:
|
case Coin.epicCash:
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
case Coin.wownero:
|
case Coin.wownero:
|
||||||
|
@ -260,6 +242,8 @@ extension CoinExt on Coin {
|
||||||
case Coin.ethereum:
|
case Coin.ethereum:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
case Coin.firo:
|
case Coin.firo:
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
|
@ -284,6 +268,7 @@ extension CoinExt on Coin {
|
||||||
bool get isTestNet {
|
bool get isTestNet {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
case Coin.litecoin:
|
case Coin.litecoin:
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
case Coin.dogecoin:
|
case Coin.dogecoin:
|
||||||
|
@ -303,6 +288,7 @@ extension CoinExt on Coin {
|
||||||
|
|
||||||
case Coin.dogecoinTestNet:
|
case Coin.dogecoinTestNet:
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
case Coin.bitcoincashTestnet:
|
case Coin.bitcoincashTestnet:
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
|
@ -314,6 +300,7 @@ extension CoinExt on Coin {
|
||||||
Coin get mainNetVersion {
|
Coin get mainNetVersion {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
case Coin.litecoin:
|
case Coin.litecoin:
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
case Coin.dogecoin:
|
case Coin.dogecoin:
|
||||||
|
@ -337,6 +324,9 @@ extension CoinExt on Coin {
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
return Coin.bitcoin;
|
return Coin.bitcoin;
|
||||||
|
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
|
return Coin.bitcoinFrost;
|
||||||
|
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
return Coin.litecoin;
|
return Coin.litecoin;
|
||||||
|
|
||||||
|
@ -364,6 +354,10 @@ extension CoinExt on Coin {
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
return AddressType.p2wpkh;
|
return AddressType.p2wpkh;
|
||||||
|
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
|
return AddressType.frostMS;
|
||||||
|
|
||||||
case Coin.eCash:
|
case Coin.eCash:
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
case Coin.bitcoincashTestnet:
|
case Coin.bitcoincashTestnet:
|
||||||
|
|
|
@ -44,6 +44,8 @@ extension DerivePathTypeExt on DerivePathType {
|
||||||
case Coin.ethereum: // TODO: do we need something here?
|
case Coin.ethereum: // TODO: do we need something here?
|
||||||
return DerivePathType.eth;
|
return DerivePathType.eth;
|
||||||
|
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
case Coin.epicCash:
|
case Coin.epicCash:
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
case Coin.wownero:
|
case Coin.wownero:
|
||||||
|
|
|
@ -170,30 +170,10 @@ class Bitcoin extends Bip39HDCurrency with PaynymCurrencyInterface {
|
||||||
NodeModel get defaultNode {
|
NodeModel get defaultNode {
|
||||||
switch (network) {
|
switch (network) {
|
||||||
case CryptoCurrencyNetwork.main:
|
case CryptoCurrencyNetwork.main:
|
||||||
return NodeModel(
|
return DefaultNodes.bitcoin;
|
||||||
host: "bitcoin.stackwallet.com",
|
|
||||||
port: 50002,
|
|
||||||
name: DefaultNodes.defaultName,
|
|
||||||
id: DefaultNodes.buildId(Coin.bitcoin),
|
|
||||||
useSSL: true,
|
|
||||||
enabled: true,
|
|
||||||
coinName: Coin.bitcoin.name,
|
|
||||||
isFailover: true,
|
|
||||||
isDown: false,
|
|
||||||
);
|
|
||||||
|
|
||||||
case CryptoCurrencyNetwork.test:
|
case CryptoCurrencyNetwork.test:
|
||||||
return NodeModel(
|
return DefaultNodes.bitcoinTestnet;
|
||||||
host: "bitcoin-testnet.stackwallet.com",
|
|
||||||
port: 51002,
|
|
||||||
name: DefaultNodes.defaultName,
|
|
||||||
id: DefaultNodes.buildId(Coin.bitcoinTestNet),
|
|
||||||
useSSL: true,
|
|
||||||
enabled: true,
|
|
||||||
coinName: Coin.bitcoinTestNet.name,
|
|
||||||
isFailover: true,
|
|
||||||
isDown: false,
|
|
||||||
);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
|
|
65
lib/wallets/crypto_currency/coins/bitcoin_frost.dart
Normal file
65
lib/wallets/crypto_currency/coins/bitcoin_frost.dart
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:stackwallet/models/node_model.dart';
|
||||||
|
import 'package:stackwallet/utilities/default_nodes.dart';
|
||||||
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
|
import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
|
||||||
|
import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart';
|
||||||
|
import 'package:stackwallet/wallets/crypto_currency/intermediate/private_key_currency.dart';
|
||||||
|
|
||||||
|
class BitcoinFrost extends FrostCurrency {
|
||||||
|
BitcoinFrost(super.network) {
|
||||||
|
switch (network) {
|
||||||
|
case CryptoCurrencyNetwork.main:
|
||||||
|
coin = Coin.bitcoin;
|
||||||
|
case CryptoCurrencyNetwork.test:
|
||||||
|
coin = Coin.bitcoinTestNet;
|
||||||
|
default:
|
||||||
|
throw Exception("Unsupported network: $network");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get minConfirms => 1;
|
||||||
|
|
||||||
|
@override
|
||||||
|
NodeModel get defaultNode {
|
||||||
|
switch (network) {
|
||||||
|
case CryptoCurrencyNetwork.main:
|
||||||
|
return DefaultNodes.bitcoin;
|
||||||
|
|
||||||
|
case CryptoCurrencyNetwork.test:
|
||||||
|
return DefaultNodes.bitcoinTestnet;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get genesisHash {
|
||||||
|
switch (network) {
|
||||||
|
case CryptoCurrencyNetwork.main:
|
||||||
|
return "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";
|
||||||
|
case CryptoCurrencyNetwork.test:
|
||||||
|
return "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943";
|
||||||
|
default:
|
||||||
|
throw Exception("Unsupported network: $network");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String pubKeyToScriptHash({required Uint8List pubKey}) {
|
||||||
|
try {
|
||||||
|
return Bip39HDCurrency.convertBytesToScriptHash(pubKey);
|
||||||
|
} catch (e) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool validateAddress(String address) {
|
||||||
|
// TODO: implement validateAddress for frost addresses
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
|
||||||
|
|
||||||
|
abstract class FrostCurrency extends CryptoCurrency {
|
||||||
|
FrostCurrency(super.network);
|
||||||
|
|
||||||
|
String pubKeyToScriptHash({required Uint8List pubKey});
|
||||||
|
}
|
38
lib/wallets/isar/models/frost_wallet_info.dart
Normal file
38
lib/wallets/isar/models/frost_wallet_info.dart
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:stackwallet/wallets/isar/isar_id_interface.dart';
|
||||||
|
|
||||||
|
part 'frost_wallet_info.g.dart';
|
||||||
|
|
||||||
|
@Collection(accessor: "frostWalletInfo", inheritance: false)
|
||||||
|
class FrostWalletInfo implements IsarId {
|
||||||
|
@override
|
||||||
|
Id id = Isar.autoIncrement;
|
||||||
|
|
||||||
|
@Index(unique: true, replace: false)
|
||||||
|
final String walletId;
|
||||||
|
|
||||||
|
final List<String> knownSalts;
|
||||||
|
|
||||||
|
FrostWalletInfo({
|
||||||
|
required this.walletId,
|
||||||
|
required this.knownSalts,
|
||||||
|
});
|
||||||
|
|
||||||
|
FrostWalletInfo copyWith({
|
||||||
|
List<String>? knownSalts,
|
||||||
|
}) {
|
||||||
|
return FrostWalletInfo(
|
||||||
|
walletId: walletId,
|
||||||
|
knownSalts: knownSalts ?? this.knownSalts,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateKnownSalts(
|
||||||
|
List<String> knownSalts, {
|
||||||
|
required Isar isar,
|
||||||
|
}) async {
|
||||||
|
// await isar.writeTxn(() async {
|
||||||
|
// await isar.
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
}
|
818
lib/wallets/isar/models/frost_wallet_info.g.dart
Normal file
818
lib/wallets/isar/models/frost_wallet_info.g.dart
Normal file
|
@ -0,0 +1,818 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'frost_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 GetFrostWalletInfoCollection on Isar {
|
||||||
|
IsarCollection<FrostWalletInfo> get frostWalletInfo => this.collection();
|
||||||
|
}
|
||||||
|
|
||||||
|
const FrostWalletInfoSchema = CollectionSchema(
|
||||||
|
name: r'FrostWalletInfo',
|
||||||
|
id: -4182879703273806681,
|
||||||
|
properties: {
|
||||||
|
r'knownSalts': PropertySchema(
|
||||||
|
id: 0,
|
||||||
|
name: r'knownSalts',
|
||||||
|
type: IsarType.stringList,
|
||||||
|
),
|
||||||
|
r'walletId': PropertySchema(
|
||||||
|
id: 1,
|
||||||
|
name: r'walletId',
|
||||||
|
type: IsarType.string,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
estimateSize: _frostWalletInfoEstimateSize,
|
||||||
|
serialize: _frostWalletInfoSerialize,
|
||||||
|
deserialize: _frostWalletInfoDeserialize,
|
||||||
|
deserializeProp: _frostWalletInfoDeserializeProp,
|
||||||
|
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: _frostWalletInfoGetId,
|
||||||
|
getLinks: _frostWalletInfoGetLinks,
|
||||||
|
attach: _frostWalletInfoAttach,
|
||||||
|
version: '3.0.5',
|
||||||
|
);
|
||||||
|
|
||||||
|
int _frostWalletInfoEstimateSize(
|
||||||
|
FrostWalletInfo object,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
var bytesCount = offsets.last;
|
||||||
|
bytesCount += 3 + object.knownSalts.length * 3;
|
||||||
|
{
|
||||||
|
for (var i = 0; i < object.knownSalts.length; i++) {
|
||||||
|
final value = object.knownSalts[i];
|
||||||
|
bytesCount += value.length * 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bytesCount += 3 + object.walletId.length * 3;
|
||||||
|
return bytesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _frostWalletInfoSerialize(
|
||||||
|
FrostWalletInfo object,
|
||||||
|
IsarWriter writer,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
writer.writeStringList(offsets[0], object.knownSalts);
|
||||||
|
writer.writeString(offsets[1], object.walletId);
|
||||||
|
}
|
||||||
|
|
||||||
|
FrostWalletInfo _frostWalletInfoDeserialize(
|
||||||
|
Id id,
|
||||||
|
IsarReader reader,
|
||||||
|
List<int> offsets,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
final object = FrostWalletInfo(
|
||||||
|
knownSalts: reader.readStringList(offsets[0]) ?? [],
|
||||||
|
walletId: reader.readString(offsets[1]),
|
||||||
|
);
|
||||||
|
object.id = id;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
P _frostWalletInfoDeserializeProp<P>(
|
||||||
|
IsarReader reader,
|
||||||
|
int propertyId,
|
||||||
|
int offset,
|
||||||
|
Map<Type, List<int>> allOffsets,
|
||||||
|
) {
|
||||||
|
switch (propertyId) {
|
||||||
|
case 0:
|
||||||
|
return (reader.readStringList(offset) ?? []) as P;
|
||||||
|
case 1:
|
||||||
|
return (reader.readString(offset)) as P;
|
||||||
|
default:
|
||||||
|
throw IsarError('Unknown property with id $propertyId');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Id _frostWalletInfoGetId(FrostWalletInfo object) {
|
||||||
|
return object.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IsarLinkBase<dynamic>> _frostWalletInfoGetLinks(FrostWalletInfo object) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _frostWalletInfoAttach(
|
||||||
|
IsarCollection<dynamic> col, Id id, FrostWalletInfo object) {
|
||||||
|
object.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FrostWalletInfoByIndex on IsarCollection<FrostWalletInfo> {
|
||||||
|
Future<FrostWalletInfo?> getByWalletId(String walletId) {
|
||||||
|
return getByIndex(r'walletId', [walletId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
FrostWalletInfo? getByWalletIdSync(String walletId) {
|
||||||
|
return getByIndexSync(r'walletId', [walletId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> deleteByWalletId(String walletId) {
|
||||||
|
return deleteByIndex(r'walletId', [walletId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool deleteByWalletIdSync(String walletId) {
|
||||||
|
return deleteByIndexSync(r'walletId', [walletId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<FrostWalletInfo?>> getAllByWalletId(List<String> walletIdValues) {
|
||||||
|
final values = walletIdValues.map((e) => [e]).toList();
|
||||||
|
return getAllByIndex(r'walletId', values);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<FrostWalletInfo?> getAllByWalletIdSync(List<String> walletIdValues) {
|
||||||
|
final values = walletIdValues.map((e) => [e]).toList();
|
||||||
|
return getAllByIndexSync(r'walletId', values);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> deleteAllByWalletId(List<String> walletIdValues) {
|
||||||
|
final values = walletIdValues.map((e) => [e]).toList();
|
||||||
|
return deleteAllByIndex(r'walletId', values);
|
||||||
|
}
|
||||||
|
|
||||||
|
int deleteAllByWalletIdSync(List<String> walletIdValues) {
|
||||||
|
final values = walletIdValues.map((e) => [e]).toList();
|
||||||
|
return deleteAllByIndexSync(r'walletId', values);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Id> putByWalletId(FrostWalletInfo object) {
|
||||||
|
return putByIndex(r'walletId', object);
|
||||||
|
}
|
||||||
|
|
||||||
|
Id putByWalletIdSync(FrostWalletInfo object, {bool saveLinks = true}) {
|
||||||
|
return putByIndexSync(r'walletId', object, saveLinks: saveLinks);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Id>> putAllByWalletId(List<FrostWalletInfo> objects) {
|
||||||
|
return putAllByIndex(r'walletId', objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Id> putAllByWalletIdSync(List<FrostWalletInfo> objects,
|
||||||
|
{bool saveLinks = true}) {
|
||||||
|
return putAllByIndexSync(r'walletId', objects, saveLinks: saveLinks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FrostWalletInfoQueryWhereSort
|
||||||
|
on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QWhere> {
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterWhere> anyId() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(const IdWhereClause.any());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FrostWalletInfoQueryWhere
|
||||||
|
on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QWhereClause> {
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterWhereClause> idEqualTo(
|
||||||
|
Id id) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(IdWhereClause.between(
|
||||||
|
lower: id,
|
||||||
|
upper: id,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterWhereClause>
|
||||||
|
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<FrostWalletInfo, FrostWalletInfo, QAfterWhereClause>
|
||||||
|
idGreaterThan(Id id, {bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.greaterThan(lower: id, includeLower: include),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterWhereClause> idLessThan(
|
||||||
|
Id id,
|
||||||
|
{bool include = false}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(
|
||||||
|
IdWhereClause.lessThan(upper: id, includeUpper: include),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterWhereClause> 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<FrostWalletInfo, FrostWalletInfo, QAfterWhereClause>
|
||||||
|
walletIdEqualTo(String walletId) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addWhereClause(IndexWhereClause.equalTo(
|
||||||
|
indexName: r'walletId',
|
||||||
|
value: [walletId],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterWhereClause>
|
||||||
|
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 FrostWalletInfoQueryFilter
|
||||||
|
on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QFilterCondition> {
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
idEqualTo(Id value) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.equalTo(
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
idGreaterThan(
|
||||||
|
Id value, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
idLessThan(
|
||||||
|
Id value, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'id',
|
||||||
|
value: value,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
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<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsElementEqualTo(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.equalTo(
|
||||||
|
property: r'knownSalts',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsElementGreaterThan(
|
||||||
|
String value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'knownSalts',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsElementLessThan(
|
||||||
|
String value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'knownSalts',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsElementBetween(
|
||||||
|
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'knownSalts',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsElementStartsWith(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.startsWith(
|
||||||
|
property: r'knownSalts',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsElementEndsWith(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.endsWith(
|
||||||
|
property: r'knownSalts',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsElementContains(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.contains(
|
||||||
|
property: r'knownSalts',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsElementMatches(String pattern, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.matches(
|
||||||
|
property: r'knownSalts',
|
||||||
|
wildcard: pattern,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsElementIsEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.equalTo(
|
||||||
|
property: r'knownSalts',
|
||||||
|
value: '',
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsElementIsNotEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||||
|
property: r'knownSalts',
|
||||||
|
value: '',
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsLengthEqualTo(int length) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.listLength(
|
||||||
|
r'knownSalts',
|
||||||
|
length,
|
||||||
|
true,
|
||||||
|
length,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsIsEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.listLength(
|
||||||
|
r'knownSalts',
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsIsNotEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.listLength(
|
||||||
|
r'knownSalts',
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
999999,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsLengthLessThan(
|
||||||
|
int length, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.listLength(
|
||||||
|
r'knownSalts',
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
length,
|
||||||
|
include,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsLengthGreaterThan(
|
||||||
|
int length, {
|
||||||
|
bool include = false,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.listLength(
|
||||||
|
r'knownSalts',
|
||||||
|
length,
|
||||||
|
include,
|
||||||
|
999999,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
knownSaltsLengthBetween(
|
||||||
|
int lower,
|
||||||
|
int upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.listLength(
|
||||||
|
r'knownSalts',
|
||||||
|
lower,
|
||||||
|
includeLower,
|
||||||
|
upper,
|
||||||
|
includeUpper,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
walletIdEqualTo(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.equalTo(
|
||||||
|
property: r'walletId',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
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<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
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<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
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<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
walletIdStartsWith(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.startsWith(
|
||||||
|
property: r'walletId',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
walletIdEndsWith(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.endsWith(
|
||||||
|
property: r'walletId',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
walletIdContains(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.contains(
|
||||||
|
property: r'walletId',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
walletIdMatches(String pattern, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.matches(
|
||||||
|
property: r'walletId',
|
||||||
|
wildcard: pattern,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
walletIdIsEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.equalTo(
|
||||||
|
property: r'walletId',
|
||||||
|
value: '',
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
|
||||||
|
walletIdIsNotEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||||
|
property: r'walletId',
|
||||||
|
value: '',
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FrostWalletInfoQueryObject
|
||||||
|
on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QFilterCondition> {}
|
||||||
|
|
||||||
|
extension FrostWalletInfoQueryLinks
|
||||||
|
on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QFilterCondition> {}
|
||||||
|
|
||||||
|
extension FrostWalletInfoQuerySortBy
|
||||||
|
on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QSortBy> {
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
|
||||||
|
sortByWalletId() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'walletId', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
|
||||||
|
sortByWalletIdDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'walletId', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FrostWalletInfoQuerySortThenBy
|
||||||
|
on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QSortThenBy> {
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy> thenById() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'id', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy> thenByIdDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'id', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
|
||||||
|
thenByWalletId() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'walletId', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
|
||||||
|
thenByWalletIdDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'walletId', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FrostWalletInfoQueryWhereDistinct
|
||||||
|
on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QDistinct> {
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QDistinct>
|
||||||
|
distinctByKnownSalts() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'knownSalts');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, FrostWalletInfo, QDistinct> distinctByWalletId(
|
||||||
|
{bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'walletId', caseSensitive: caseSensitive);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FrostWalletInfoQueryProperty
|
||||||
|
on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QQueryProperty> {
|
||||||
|
QueryBuilder<FrostWalletInfo, int, QQueryOperations> idProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, List<String>, QQueryOperations>
|
||||||
|
knownSaltsProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'knownSalts');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<FrostWalletInfo, String, QQueryOperations> walletIdProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'walletId');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -265,6 +265,7 @@ const _WalletInfomainAddressTypeEnumValueMap = {
|
||||||
'spark': 10,
|
'spark': 10,
|
||||||
'stellar': 11,
|
'stellar': 11,
|
||||||
'tezos': 12,
|
'tezos': 12,
|
||||||
|
'frostMS': 13,
|
||||||
};
|
};
|
||||||
const _WalletInfomainAddressTypeValueEnumMap = {
|
const _WalletInfomainAddressTypeValueEnumMap = {
|
||||||
0: AddressType.p2pkh,
|
0: AddressType.p2pkh,
|
||||||
|
@ -280,6 +281,7 @@ const _WalletInfomainAddressTypeValueEnumMap = {
|
||||||
10: AddressType.spark,
|
10: AddressType.spark,
|
||||||
11: AddressType.stellar,
|
11: AddressType.stellar,
|
||||||
12: AddressType.tezos,
|
12: AddressType.tezos,
|
||||||
|
13: AddressType.frostMS,
|
||||||
};
|
};
|
||||||
|
|
||||||
Id _walletInfoGetId(WalletInfo object) {
|
Id _walletInfoGetId(WalletInfo object) {
|
||||||
|
|
475
lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
Normal file
475
lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
Normal file
|
@ -0,0 +1,475 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:frostdart/frostdart.dart' as frost;
|
||||||
|
import 'package:frostdart/frostdart_bindings_generated.dart';
|
||||||
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:stackwallet/electrumx_rpc/cached_electrumx_client.dart';
|
||||||
|
import 'package:stackwallet/electrumx_rpc/electrumx_client.dart';
|
||||||
|
import 'package:stackwallet/models/balance.dart';
|
||||||
|
import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
|
||||||
|
import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
|
||||||
|
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
||||||
|
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||||
|
import 'package:stackwallet/utilities/extensions/extensions.dart';
|
||||||
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin_frost.dart';
|
||||||
|
import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
|
||||||
|
import 'package:stackwallet/wallets/crypto_currency/intermediate/private_key_currency.dart';
|
||||||
|
import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
|
||||||
|
import 'package:stackwallet/wallets/models/tx_data.dart';
|
||||||
|
import 'package:stackwallet/wallets/wallet/wallet.dart';
|
||||||
|
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/private_key_interface.dart';
|
||||||
|
|
||||||
|
class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
|
||||||
|
with PrivateKeyInterface {
|
||||||
|
FrostWalletInfo get frostInfo => throw UnimplementedError();
|
||||||
|
|
||||||
|
late ElectrumXClient electrumXClient;
|
||||||
|
late CachedElectrumXClient electrumXCachedClient;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get isarTransactionVersion => 2;
|
||||||
|
|
||||||
|
BitcoinFrostWallet(CryptoCurrencyNetwork network)
|
||||||
|
: super(BitcoinFrost(network) as T);
|
||||||
|
|
||||||
|
@override
|
||||||
|
FilterOperation? get changeAddressFilterOperation => FilterGroup.and(
|
||||||
|
[
|
||||||
|
FilterCondition.equalTo(
|
||||||
|
property: r"type",
|
||||||
|
value: info.mainAddressType,
|
||||||
|
),
|
||||||
|
const FilterCondition.equalTo(
|
||||||
|
property: r"subType",
|
||||||
|
value: AddressSubType.change,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
FilterOperation? get receivingAddressFilterOperation => FilterGroup.and(
|
||||||
|
[
|
||||||
|
FilterCondition.equalTo(
|
||||||
|
property: r"type",
|
||||||
|
value: info.mainAddressType,
|
||||||
|
),
|
||||||
|
const FilterCondition.equalTo(
|
||||||
|
property: r"subType",
|
||||||
|
value: AddressSubType.receiving,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Future<List<Address>> fetchAddressesForElectrumXScan() async {
|
||||||
|
// final allAddresses = await mainDB
|
||||||
|
// .getAddresses(walletId)
|
||||||
|
// .filter()
|
||||||
|
// .typeEqualTo(AddressType.frostMS)
|
||||||
|
// .and()
|
||||||
|
// .group(
|
||||||
|
// (q) => q
|
||||||
|
// .subTypeEqualTo(AddressSubType.receiving)
|
||||||
|
// .or()
|
||||||
|
// .subTypeEqualTo(AddressSubType.change),
|
||||||
|
// )
|
||||||
|
// .findAll();
|
||||||
|
// return allAddresses;
|
||||||
|
// }
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> updateTransactions() {
|
||||||
|
// TODO: implement updateTransactions
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
int estimateTxFee({required int vSize, required int feeRatePerKB}) {
|
||||||
|
return vSize * (feeRatePerKB / 1000).ceil();
|
||||||
|
}
|
||||||
|
|
||||||
|
Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||||
|
return Amount(
|
||||||
|
rawValue: BigInt.from(
|
||||||
|
((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() *
|
||||||
|
(feeRatePerKB / 1000).ceil()),
|
||||||
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> checkSaveInitialReceivingAddress() {
|
||||||
|
// TODO: implement checkSaveInitialReceivingAddress
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<TxData> confirmSend({required TxData txData}) {
|
||||||
|
// TODO: implement confirmSend
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Amount> estimateFeeFor(Amount amount, int feeRate) {
|
||||||
|
// TODO: implement estimateFeeFor
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement fees
|
||||||
|
Future<FeeObject> get fees => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<TxData> prepareSend({required TxData txData}) {
|
||||||
|
// TODO: implement prepareSendpu
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> recover({
|
||||||
|
required bool isRescan,
|
||||||
|
String? serializedKeys,
|
||||||
|
String? multisigConfig,
|
||||||
|
}) async {
|
||||||
|
if (serializedKeys == null || multisigConfig == null) {
|
||||||
|
throw Exception(
|
||||||
|
"Failed to recover $runtimeType: "
|
||||||
|
"Missing serializedKeys and/or multisigConfig.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await refreshMutex.protect(() async {
|
||||||
|
if (!isRescan) {
|
||||||
|
final salt = frost
|
||||||
|
.multisigSalt(
|
||||||
|
multisigConfig: multisigConfig,
|
||||||
|
)
|
||||||
|
.toHex;
|
||||||
|
final knownSalts = frostInfo.knownSalts;
|
||||||
|
if (knownSalts.contains(salt)) {
|
||||||
|
throw Exception("Known frost multisig salt found!");
|
||||||
|
}
|
||||||
|
knownSalts.add(salt);
|
||||||
|
await frostInfo.updateKnownSalts(knownSalts, isar: mainDB.isar);
|
||||||
|
}
|
||||||
|
|
||||||
|
final keys = frost.deserializeKeys(keys: serializedKeys);
|
||||||
|
await _saveSerializedKeys(serializedKeys);
|
||||||
|
await _saveMultisigConfig(multisigConfig);
|
||||||
|
|
||||||
|
final addressString = frost.addressForKeys(
|
||||||
|
network: cryptoCurrency.network == CryptoCurrencyNetwork.main
|
||||||
|
? Network.Mainnet
|
||||||
|
: Network.Testnet,
|
||||||
|
keys: keys,
|
||||||
|
);
|
||||||
|
|
||||||
|
final publicKey = frost.scriptPubKeyForKeys(keys: keys);
|
||||||
|
|
||||||
|
final address = Address(
|
||||||
|
walletId: walletId,
|
||||||
|
value: addressString,
|
||||||
|
publicKey: publicKey.toUint8ListFromHex,
|
||||||
|
derivationIndex: 0,
|
||||||
|
derivationPath: null,
|
||||||
|
subType: AddressSubType.receiving,
|
||||||
|
type: AddressType.frostMS,
|
||||||
|
);
|
||||||
|
|
||||||
|
await mainDB.updateOrPutAddresses([address]);
|
||||||
|
});
|
||||||
|
|
||||||
|
unawaited(refresh());
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"recoverFromSerializedKeys failed: $e\n$s",
|
||||||
|
level: LogLevel.Fatal,
|
||||||
|
);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> updateBalance() async {
|
||||||
|
final utxos = await mainDB.getUTXOs(walletId).findAll();
|
||||||
|
|
||||||
|
final currentChainHeight = await chainHeight;
|
||||||
|
|
||||||
|
Amount satoshiBalanceTotal = Amount(
|
||||||
|
rawValue: BigInt.zero,
|
||||||
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
);
|
||||||
|
Amount satoshiBalancePending = Amount(
|
||||||
|
rawValue: BigInt.zero,
|
||||||
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
);
|
||||||
|
Amount satoshiBalanceSpendable = Amount(
|
||||||
|
rawValue: BigInt.zero,
|
||||||
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
);
|
||||||
|
Amount satoshiBalanceBlocked = Amount(
|
||||||
|
rawValue: BigInt.zero,
|
||||||
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (final utxo in utxos) {
|
||||||
|
final utxoAmount = Amount(
|
||||||
|
rawValue: BigInt.from(utxo.value),
|
||||||
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
);
|
||||||
|
|
||||||
|
satoshiBalanceTotal += utxoAmount;
|
||||||
|
|
||||||
|
if (utxo.isBlocked) {
|
||||||
|
satoshiBalanceBlocked += utxoAmount;
|
||||||
|
} else {
|
||||||
|
if (utxo.isConfirmed(
|
||||||
|
currentChainHeight,
|
||||||
|
cryptoCurrency.minConfirms,
|
||||||
|
)) {
|
||||||
|
satoshiBalanceSpendable += utxoAmount;
|
||||||
|
} else {
|
||||||
|
satoshiBalancePending += utxoAmount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final balance = Balance(
|
||||||
|
total: satoshiBalanceTotal,
|
||||||
|
spendable: satoshiBalanceSpendable,
|
||||||
|
blockedTotal: satoshiBalanceBlocked,
|
||||||
|
pendingSpendable: satoshiBalancePending,
|
||||||
|
);
|
||||||
|
|
||||||
|
await info.updateBalance(newBalance: balance, isar: mainDB.isar);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> updateChainHeight() async {
|
||||||
|
final int height;
|
||||||
|
try {
|
||||||
|
final result = await electrumXClient.getBlockHeadTip();
|
||||||
|
height = result["height"] as int;
|
||||||
|
} catch (e) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
await info.updateCachedChainHeight(
|
||||||
|
newHeight: height,
|
||||||
|
isar: mainDB.isar,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> pingCheck() async {
|
||||||
|
try {
|
||||||
|
final result = await electrumXClient.ping();
|
||||||
|
return result;
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> updateNode() async {
|
||||||
|
await _updateElectrumX();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> updateUTXOs() async {
|
||||||
|
final address = await getCurrentReceivingAddress();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final scriptHash = cryptoCurrency.pubKeyToScriptHash(
|
||||||
|
pubKey: Uint8List.fromList(address!.publicKey),
|
||||||
|
);
|
||||||
|
|
||||||
|
final utxos = await electrumXClient.getUTXOs(scripthash: scriptHash);
|
||||||
|
|
||||||
|
final List<UTXO> outputArray = [];
|
||||||
|
|
||||||
|
for (int i = 0; i < utxos.length; i++) {
|
||||||
|
final utxo = await _parseUTXO(
|
||||||
|
jsonUTXO: utxos[i],
|
||||||
|
);
|
||||||
|
|
||||||
|
outputArray.add(utxo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await mainDB.updateUTXOs(walletId, outputArray);
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Output fetch unsuccessful: $e\n$s",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =================== Secure storage ========================================
|
||||||
|
|
||||||
|
Future<String?> get getSerializedKeys async =>
|
||||||
|
await secureStorageInterface.read(
|
||||||
|
key: "{$walletId}_serializedFROSTKeys",
|
||||||
|
);
|
||||||
|
Future<void> _saveSerializedKeys(String keys) async {
|
||||||
|
final current = await getSerializedKeys;
|
||||||
|
|
||||||
|
if (current == null) {
|
||||||
|
// do nothing
|
||||||
|
} else if (current == keys) {
|
||||||
|
// should never occur
|
||||||
|
} else {
|
||||||
|
// save current as prev gen before updating current
|
||||||
|
await secureStorageInterface.write(
|
||||||
|
key: "{$walletId}_serializedFROSTKeysPrevGen",
|
||||||
|
value: current,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await secureStorageInterface.write(
|
||||||
|
key: "{$walletId}_serializedFROSTKeys",
|
||||||
|
value: keys,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String?> get getSerializedKeysPrevGen async =>
|
||||||
|
await secureStorageInterface.read(
|
||||||
|
key: "{$walletId}_serializedFROSTKeysPrevGen",
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<String?> get multisigConfig async => await secureStorageInterface.read(
|
||||||
|
key: "{$walletId}_multisigConfig",
|
||||||
|
);
|
||||||
|
Future<String?> get multisigConfigPrevGen async =>
|
||||||
|
await secureStorageInterface.read(
|
||||||
|
key: "{$walletId}_multisigConfigPrevGen",
|
||||||
|
);
|
||||||
|
Future<void> _saveMultisigConfig(String multisigConfig) async {
|
||||||
|
final current = await this.multisigConfig;
|
||||||
|
|
||||||
|
if (current == null) {
|
||||||
|
// do nothing
|
||||||
|
} else if (current == multisigConfig) {
|
||||||
|
// should never occur
|
||||||
|
} else {
|
||||||
|
// save current as prev gen before updating current
|
||||||
|
await secureStorageInterface.write(
|
||||||
|
key: "{$walletId}_multisigConfigPrevGen",
|
||||||
|
value: current,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await secureStorageInterface.write(
|
||||||
|
key: "{$walletId}_multisigConfig",
|
||||||
|
value: multisigConfig,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Uint8List?> get multisigId async {
|
||||||
|
final id = await secureStorageInterface.read(
|
||||||
|
key: "{$walletId}_multisigIdFROST",
|
||||||
|
);
|
||||||
|
if (id == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return id.toUint8ListFromHex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> saveMultisigId(Uint8List id) async =>
|
||||||
|
await secureStorageInterface.write(
|
||||||
|
key: "{$walletId}_multisigIdFROST",
|
||||||
|
value: id.toHex,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<String?> get recoveryString async => await secureStorageInterface.read(
|
||||||
|
key: "{$walletId}_recoveryStringFROST",
|
||||||
|
);
|
||||||
|
Future<void> saveRecoveryString(String recoveryString) async =>
|
||||||
|
await secureStorageInterface.write(
|
||||||
|
key: "{$walletId}_recoveryStringFROST",
|
||||||
|
value: recoveryString,
|
||||||
|
);
|
||||||
|
|
||||||
|
// =================== Private ===============================================
|
||||||
|
|
||||||
|
Future<ElectrumXNode> _getCurrentElectrumXNode() async {
|
||||||
|
final node = getCurrentNode();
|
||||||
|
|
||||||
|
return ElectrumXNode(
|
||||||
|
address: node.host,
|
||||||
|
port: node.port,
|
||||||
|
name: node.name,
|
||||||
|
useSSL: node.useSSL,
|
||||||
|
id: node.id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _updateElectrumX() async {
|
||||||
|
final failovers = nodeService
|
||||||
|
.failoverNodesFor(coin: cryptoCurrency.coin)
|
||||||
|
.map((e) => ElectrumXNode(
|
||||||
|
address: e.host,
|
||||||
|
port: e.port,
|
||||||
|
name: e.name,
|
||||||
|
id: e.id,
|
||||||
|
useSSL: e.useSSL,
|
||||||
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
final newNode = await _getCurrentElectrumXNode();
|
||||||
|
electrumXClient = ElectrumXClient.from(
|
||||||
|
node: newNode,
|
||||||
|
prefs: prefs,
|
||||||
|
failovers: failovers,
|
||||||
|
);
|
||||||
|
electrumXCachedClient = CachedElectrumXClient.from(
|
||||||
|
electrumXClient: electrumXClient,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<UTXO> _parseUTXO({
|
||||||
|
required Map<String, dynamic> jsonUTXO,
|
||||||
|
}) async {
|
||||||
|
final txn = await electrumXCachedClient.getTransaction(
|
||||||
|
txHash: jsonUTXO["tx_hash"] as String,
|
||||||
|
verbose: true,
|
||||||
|
coin: cryptoCurrency.coin,
|
||||||
|
);
|
||||||
|
|
||||||
|
final vout = jsonUTXO["tx_pos"] as int;
|
||||||
|
|
||||||
|
final outputs = txn["vout"] as List;
|
||||||
|
|
||||||
|
String? scriptPubKey;
|
||||||
|
String? utxoOwnerAddress;
|
||||||
|
// get UTXO owner address
|
||||||
|
for (final output in outputs) {
|
||||||
|
if (output["n"] == vout) {
|
||||||
|
scriptPubKey = output["scriptPubKey"]?["hex"] as String?;
|
||||||
|
utxoOwnerAddress =
|
||||||
|
output["scriptPubKey"]?["addresses"]?[0] as String? ??
|
||||||
|
output["scriptPubKey"]?["address"] as String?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final utxo = UTXO(
|
||||||
|
walletId: walletId,
|
||||||
|
txid: txn["txid"] as String,
|
||||||
|
vout: vout,
|
||||||
|
value: jsonUTXO["value"] as int,
|
||||||
|
name: "",
|
||||||
|
isBlocked: false,
|
||||||
|
blockedReason: null,
|
||||||
|
isCoinbase: txn["is_coinbase"] as bool? ?? false,
|
||||||
|
blockHash: txn["blockhash"] as String?,
|
||||||
|
blockHeight: jsonUTXO["height"] as int?,
|
||||||
|
blockTime: txn["blocktime"] as int?,
|
||||||
|
address: utxoOwnerAddress,
|
||||||
|
);
|
||||||
|
|
||||||
|
return utxo;
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
|
||||||
import 'package:stackwallet/wallets/isar/models/wallet_info.dart';
|
import 'package:stackwallet/wallets/isar/models/wallet_info.dart';
|
||||||
import 'package:stackwallet/wallets/models/tx_data.dart';
|
import 'package:stackwallet/wallets/models/tx_data.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/impl/banano_wallet.dart';
|
import 'package:stackwallet/wallets/wallet/impl/banano_wallet.dart';
|
||||||
|
import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/impl/bitcoin_wallet.dart';
|
import 'package:stackwallet/wallets/wallet/impl/bitcoin_wallet.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/impl/bitcoincash_wallet.dart';
|
import 'package:stackwallet/wallets/wallet/impl/bitcoincash_wallet.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/impl/dogecoin_wallet.dart';
|
import 'package:stackwallet/wallets/wallet/impl/dogecoin_wallet.dart';
|
||||||
|
@ -311,6 +312,11 @@ abstract class Wallet<T extends CryptoCurrency> {
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
return BitcoinWallet(CryptoCurrencyNetwork.test);
|
return BitcoinWallet(CryptoCurrencyNetwork.test);
|
||||||
|
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
return BitcoinFrostWallet(CryptoCurrencyNetwork.main);
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
|
return BitcoinFrostWallet(CryptoCurrencyNetwork.test);
|
||||||
|
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
return BitcoincashWallet(CryptoCurrencyNetwork.main);
|
return BitcoincashWallet(CryptoCurrencyNetwork.main);
|
||||||
case Coin.bitcoincashTestnet:
|
case Coin.bitcoincashTestnet:
|
||||||
|
|
|
@ -832,7 +832,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ElectrumXNode> getCurrentElectrumXNode() async {
|
Future<ElectrumXNode> _getCurrentElectrumXNode() async {
|
||||||
final node = getCurrentNode();
|
final node = getCurrentNode();
|
||||||
|
|
||||||
return ElectrumXNode(
|
return ElectrumXNode(
|
||||||
|
@ -844,7 +844,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateElectrumX({required ElectrumXNode newNode}) async {
|
Future<void> updateElectrumX() async {
|
||||||
final failovers = nodeService
|
final failovers = nodeService
|
||||||
.failoverNodesFor(coin: cryptoCurrency.coin)
|
.failoverNodesFor(coin: cryptoCurrency.coin)
|
||||||
.map((e) => ElectrumXNode(
|
.map((e) => ElectrumXNode(
|
||||||
|
@ -856,7 +856,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
||||||
))
|
))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
final newNode = await getCurrentElectrumXNode();
|
final newNode = await _getCurrentElectrumXNode();
|
||||||
electrumXClient = ElectrumXClient.from(
|
electrumXClient = ElectrumXClient.from(
|
||||||
node: newNode,
|
node: newNode,
|
||||||
prefs: prefs,
|
prefs: prefs,
|
||||||
|
@ -1160,8 +1160,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> updateNode() async {
|
Future<void> updateNode() async {
|
||||||
final node = await getCurrentElectrumXNode();
|
await updateElectrumX();
|
||||||
await updateElectrumX(newNode: node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FeeObject? _cachedFees;
|
FeeObject? _cachedFees;
|
||||||
|
|
|
@ -169,6 +169,8 @@ class _NodeCardState extends ConsumerState<NodeCard> {
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.bitcoincashTestnet:
|
case Coin.bitcoincashTestnet:
|
||||||
case Coin.eCash:
|
case Coin.eCash:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
final client = ElectrumXClient(
|
final client = ElectrumXClient(
|
||||||
host: node.host,
|
host: node.host,
|
||||||
port: node.port,
|
port: node.port,
|
||||||
|
|
|
@ -151,6 +151,8 @@ class NodeOptionsSheet extends ConsumerWidget {
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.bitcoincashTestnet:
|
case Coin.bitcoincashTestnet:
|
||||||
case Coin.eCash:
|
case Coin.eCash:
|
||||||
|
case Coin.bitcoinFrost:
|
||||||
|
case Coin.bitcoinFrostTestNet:
|
||||||
final client = ElectrumXClient(
|
final client = ElectrumXClient(
|
||||||
host: node.host,
|
host: node.host,
|
||||||
port: node.port,
|
port: node.port,
|
||||||
|
|
Loading…
Reference in a new issue