mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-16 17:27:39 +00:00
Merge remote-tracking branch 'origin/testing' into implement-name-coin
This commit is contained in:
commit
25bcb9b94d
22 changed files with 513 additions and 166 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -48,3 +48,4 @@ test/services/coins/bitcoincash/bitcoincash_wallet_test_parameters.dart
|
|||
coverage
|
||||
scripts/**/build
|
||||
/lib/external_api_keys.dart
|
||||
/test/services/coins/bitcoincash/bitcoincash_wallet_test_parameters.dart
|
||||
|
|
BIN
assets/images/wownero.png
Normal file
BIN
assets/images/wownero.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 371 KiB |
|
@ -1 +1 @@
|
|||
Subproject commit 588281a5280a62fff624e6a96cbe5dc2e2154245
|
||||
Subproject commit 9a150d8cd2c3625424b0059e6b7306f3659fdbe0
|
|
@ -1 +1 @@
|
|||
Subproject commit 6242046217abf47b61d9397ae447632b06f853fa
|
||||
Subproject commit b1e0b20621be3ebb280ab3e3de10afe0c11db073
|
|
@ -1 +1 @@
|
|||
Subproject commit cd6f9cf62afcb6c1e55b16a76374a8577d85352f
|
||||
Subproject commit 4bffa40cb60ad3d98cf0ea5b5d819f3f4895dcd6
|
|
@ -6,22 +6,26 @@ class ContactAddressEntry {
|
|||
final Coin coin;
|
||||
final String address;
|
||||
final String label;
|
||||
final String? other;
|
||||
|
||||
const ContactAddressEntry({
|
||||
required this.coin,
|
||||
required this.address,
|
||||
required this.label,
|
||||
this.other,
|
||||
});
|
||||
|
||||
ContactAddressEntry copyWith({
|
||||
Coin? coin,
|
||||
String? address,
|
||||
String? label,
|
||||
String? other,
|
||||
}) {
|
||||
return ContactAddressEntry(
|
||||
coin: coin ?? this.coin,
|
||||
address: address ?? this.address,
|
||||
label: label ?? this.label,
|
||||
other: other ?? this.other,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -30,6 +34,7 @@ class ContactAddressEntry {
|
|||
coin: Coin.values.byName(jsonObject["coin"] as String),
|
||||
address: jsonObject["address"] as String,
|
||||
label: jsonObject["label"] as String,
|
||||
other: jsonObject["other"] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -38,6 +43,7 @@ class ContactAddressEntry {
|
|||
"label": label,
|
||||
"address": address,
|
||||
"coin": coin.name,
|
||||
"other": other ?? "",
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
|
|||
coin: manager.coin,
|
||||
address: await manager.currentReceivingAddress,
|
||||
label: "Current Receiving",
|
||||
other: manager.walletName,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -208,6 +208,16 @@ class ContactPopUp extends ConsumerWidget {
|
|||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (contact.id == "default")
|
||||
Text(
|
||||
e.other!,
|
||||
style:
|
||||
STextStyles.itemSubtitle12,
|
||||
),
|
||||
if (contact.id == "default")
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(
|
||||
"${e.label} (${e.coin.ticker})",
|
||||
style: STextStyles.itemSubtitle12,
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
@ -8,6 +11,85 @@ import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
|||
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:flutter_libepiccash/git_versions.dart' as EPIC_VERSIONS;
|
||||
import 'package:flutter_libmonero/git_versions.dart' as MONERO_VERSIONS;
|
||||
import 'package:lelantus/git_versions.dart' as FIRO_VERSIONS;
|
||||
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
const kGithubAPI = "https://api.github.com";
|
||||
const kGithubSearch = "/search/commits";
|
||||
const kGithubHead = "/repos";
|
||||
|
||||
enum CommitStatus { isHead, isOldCommit, notACommit, notLoaded }
|
||||
|
||||
Future<bool> doesCommitExist(
|
||||
String organization,
|
||||
String project,
|
||||
String commit,
|
||||
) async {
|
||||
Logging.instance.log("doesCommitExist", level: LogLevel.Info);
|
||||
final Client client = Client();
|
||||
try {
|
||||
final uri = Uri.parse(
|
||||
"$kGithubAPI$kGithubHead/$organization/$project/commits/$commit");
|
||||
|
||||
final commitQuery = await client.get(
|
||||
uri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
);
|
||||
|
||||
final response = jsonDecode(commitQuery.body.toString());
|
||||
Logging.instance.log("doesCommitExist $project $commit $response",
|
||||
level: LogLevel.Info);
|
||||
bool isThereCommit;
|
||||
try {
|
||||
isThereCommit = response['sha'] == commit;
|
||||
Logging.instance
|
||||
.log("isThereCommit $isThereCommit", level: LogLevel.Info);
|
||||
return isThereCommit;
|
||||
} catch (e, s) {
|
||||
return false;
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e $s", level: LogLevel.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> isHeadCommit(
|
||||
String organization,
|
||||
String project,
|
||||
String branch,
|
||||
String commit,
|
||||
) async {
|
||||
Logging.instance.log("doesCommitExist", level: LogLevel.Info);
|
||||
final Client client = Client();
|
||||
try {
|
||||
final uri = Uri.parse(
|
||||
"$kGithubAPI$kGithubHead/$organization/$project/commits/$branch");
|
||||
|
||||
final commitQuery = await client.get(
|
||||
uri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
);
|
||||
|
||||
final response = jsonDecode(commitQuery.body.toString());
|
||||
Logging.instance.log("isHeadCommit $project $commit $branch $response",
|
||||
level: LogLevel.Info);
|
||||
bool isHead;
|
||||
try {
|
||||
isHead = response['sha'] == commit;
|
||||
Logging.instance.log("isHead $isHead", level: LogLevel.Info);
|
||||
return isHead;
|
||||
} catch (e, s) {
|
||||
return false;
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e $s", level: LogLevel.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class AboutView extends ConsumerWidget {
|
||||
const AboutView({Key? key}) : super(key: key);
|
||||
|
@ -16,6 +98,26 @@ class AboutView extends ConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
String firoCommit = FIRO_VERSIONS.getPluginVersion();
|
||||
String epicCashCommit = EPIC_VERSIONS.getPluginVersion();
|
||||
String moneroCommit = MONERO_VERSIONS.getPluginVersion();
|
||||
List<Future> futureFiroList = [
|
||||
doesCommitExist("cypherstack", "flutter_liblelantus", firoCommit),
|
||||
isHeadCommit("cypherstack", "flutter_liblelantus", "main", firoCommit),
|
||||
];
|
||||
Future commitFiroFuture = Future.wait(futureFiroList);
|
||||
List<Future> futureEpicList = [
|
||||
doesCommitExist("cypherstack", "flutter_libepiccash", epicCashCommit),
|
||||
isHeadCommit(
|
||||
"cypherstack", "flutter_libepiccash", "main", epicCashCommit),
|
||||
];
|
||||
Future commitEpicFuture = Future.wait(futureEpicList);
|
||||
List<Future> futureMoneroList = [
|
||||
doesCommitExist("cypherstack", "flutter_libmonero", moneroCommit),
|
||||
isHeadCommit("cypherstack", "flutter_libmonero", "main", moneroCommit),
|
||||
];
|
||||
Future commitMoneroFuture = Future.wait(futureMoneroList);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: CFColors.almostWhite,
|
||||
appBar: AppBar(
|
||||
|
@ -142,6 +244,186 @@ class AboutView extends ConsumerWidget {
|
|||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: commitFiroFuture,
|
||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||
bool commitExists = false;
|
||||
bool isHead = false;
|
||||
CommitStatus stateOfCommit = CommitStatus.notLoaded;
|
||||
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
commitExists = snapshot.data![0] as bool;
|
||||
isHead = snapshot.data![1] as bool;
|
||||
if (commitExists && isHead) {
|
||||
stateOfCommit = CommitStatus.isHead;
|
||||
} else if (commitExists) {
|
||||
stateOfCommit = CommitStatus.isOldCommit;
|
||||
} else {
|
||||
stateOfCommit = CommitStatus.notACommit;
|
||||
}
|
||||
}
|
||||
TextStyle indicationStyle =
|
||||
STextStyles.itemSubtitle;
|
||||
switch (stateOfCommit) {
|
||||
case CommitStatus.isHead:
|
||||
indicationStyle = STextStyles.itemSubtitle
|
||||
.copyWith(color: CFColors.stackGreen);
|
||||
break;
|
||||
case CommitStatus.isOldCommit:
|
||||
indicationStyle = STextStyles.itemSubtitle
|
||||
.copyWith(color: CFColors.stackYellow);
|
||||
break;
|
||||
case CommitStatus.notACommit:
|
||||
indicationStyle = STextStyles.itemSubtitle
|
||||
.copyWith(color: CFColors.stackRed);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return RoundedWhiteContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
"Firo Build Commit",
|
||||
style: STextStyles.titleBold12,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
SelectableText(
|
||||
firoCommit,
|
||||
style: indicationStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: commitEpicFuture,
|
||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||
bool commitExists = false;
|
||||
bool isHead = false;
|
||||
CommitStatus stateOfCommit = CommitStatus.notLoaded;
|
||||
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
commitExists = snapshot.data![0] as bool;
|
||||
isHead = snapshot.data![1] as bool;
|
||||
if (commitExists && isHead) {
|
||||
stateOfCommit = CommitStatus.isHead;
|
||||
} else if (commitExists) {
|
||||
stateOfCommit = CommitStatus.isOldCommit;
|
||||
} else {
|
||||
stateOfCommit = CommitStatus.notACommit;
|
||||
}
|
||||
}
|
||||
TextStyle indicationStyle =
|
||||
STextStyles.itemSubtitle;
|
||||
switch (stateOfCommit) {
|
||||
case CommitStatus.isHead:
|
||||
indicationStyle = STextStyles.itemSubtitle
|
||||
.copyWith(color: CFColors.stackGreen);
|
||||
break;
|
||||
case CommitStatus.isOldCommit:
|
||||
indicationStyle = STextStyles.itemSubtitle
|
||||
.copyWith(color: CFColors.stackYellow);
|
||||
break;
|
||||
case CommitStatus.notACommit:
|
||||
indicationStyle = STextStyles.itemSubtitle
|
||||
.copyWith(color: CFColors.stackRed);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return RoundedWhiteContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
"Epic Cash Build Commit",
|
||||
style: STextStyles.titleBold12,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
SelectableText(
|
||||
epicCashCommit,
|
||||
style: indicationStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: commitMoneroFuture,
|
||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||
bool commitExists = false;
|
||||
bool isHead = false;
|
||||
CommitStatus stateOfCommit = CommitStatus.notLoaded;
|
||||
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
commitExists = snapshot.data![0] as bool;
|
||||
isHead = snapshot.data![1] as bool;
|
||||
if (commitExists && isHead) {
|
||||
stateOfCommit = CommitStatus.isHead;
|
||||
} else if (commitExists) {
|
||||
stateOfCommit = CommitStatus.isOldCommit;
|
||||
} else {
|
||||
stateOfCommit = CommitStatus.notACommit;
|
||||
}
|
||||
}
|
||||
TextStyle indicationStyle =
|
||||
STextStyles.itemSubtitle;
|
||||
switch (stateOfCommit) {
|
||||
case CommitStatus.isHead:
|
||||
indicationStyle = STextStyles.itemSubtitle
|
||||
.copyWith(color: CFColors.stackGreen);
|
||||
break;
|
||||
case CommitStatus.isOldCommit:
|
||||
indicationStyle = STextStyles.itemSubtitle
|
||||
.copyWith(color: CFColors.stackYellow);
|
||||
break;
|
||||
case CommitStatus.notACommit:
|
||||
indicationStyle = STextStyles.itemSubtitle
|
||||
.copyWith(color: CFColors.stackRed);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return RoundedWhiteContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
"Monero Build Commit",
|
||||
style: STextStyles.titleBold12,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
SelectableText(
|
||||
moneroCommit,
|
||||
style: indicationStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
RoundedWhiteContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
|
@ -535,6 +535,7 @@ class _NodeFormState extends ConsumerState<NodeForm> {
|
|||
case Coin.bitcoincashTestnet:
|
||||
case Coin.firoTestNet:
|
||||
case Coin.dogecoinTestNet:
|
||||
case Coin.bitcoincashTestnet:
|
||||
return false;
|
||||
|
||||
case Coin.epicCash:
|
||||
|
|
|
@ -45,7 +45,7 @@ class _ManageNodesViewState extends ConsumerState<ManageNodesView> {
|
|||
|
||||
List<Coin> coins = showTestNet
|
||||
? _coins
|
||||
: _coins.sublist(0, Coin.values.length - kTestNetCoinCount);
|
||||
: _coins.sublist(0, _coins.length - kTestNetCoinCount);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: CFColors.almostWhite,
|
||||
|
|
|
@ -189,7 +189,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
return false;
|
||||
}
|
||||
|
||||
void _logout() {
|
||||
void _logout() async {
|
||||
if (_shouldDisableAutoSyncOnLogOut) {
|
||||
// disable auto sync if it was enabled only when loading wallet
|
||||
ref.read(managerProvider).shouldAutoSync = false;
|
||||
|
@ -199,7 +199,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
if (ref.read(prefsChangeNotifierProvider).isAutoBackupEnabled &&
|
||||
ref.read(prefsChangeNotifierProvider).backupFrequencyType ==
|
||||
BackupFrequencyType.afterClosingAWallet) {
|
||||
ref.read(autoSWBServiceProvider).doBackup();
|
||||
unawaited(ref.read(autoSWBServiceProvider).doBackup());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -364,7 +364,13 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
onWillPop: _onWillPop,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
leading: AppBarBackButton(
|
||||
onPressed: () {
|
||||
_logout();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
titleSpacing: 0,
|
||||
title: Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
|
@ -376,9 +382,13 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
Text(
|
||||
ref.watch(managerProvider.select((value) => value.walletName)),
|
||||
style: STextStyles.navBarTitle,
|
||||
Expanded(
|
||||
child: Text(
|
||||
ref.watch(
|
||||
managerProvider.select((value) => value.walletName)),
|
||||
style: STextStyles.navBarTitle,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
|
@ -42,7 +42,7 @@ import 'package:stackwallet/utilities/prefs.dart';
|
|||
import 'package:tuple/tuple.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
const int MINIMUM_CONFIRMATIONS = 2;
|
||||
const int MINIMUM_CONFIRMATIONS = 1;
|
||||
const int DUST_LIMIT = 294;
|
||||
|
||||
const String GENESIS_HASH_MAINNET =
|
||||
|
|
|
@ -164,8 +164,15 @@ class Wallets extends ChangeNotifier {
|
|||
try {
|
||||
final walletId = entry.value.walletId;
|
||||
|
||||
final isVerified =
|
||||
await walletsService.isMnemonicVerified(walletId: walletId);
|
||||
late final bool isVerified;
|
||||
try {
|
||||
isVerified =
|
||||
await walletsService.isMnemonicVerified(walletId: walletId);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e $s", level: LogLevel.Warning);
|
||||
isVerified = false;
|
||||
}
|
||||
|
||||
Logging.instance.log(
|
||||
"LOADING WALLET: ${entry.value.toString()} IS VERIFIED: $isVerified",
|
||||
level: LogLevel.Info);
|
||||
|
|
|
@ -29,5 +29,8 @@ Uri getBlockExplorerTransactionUrlFor({
|
|||
"https://blockexplorer.one/bitcoin-cash/testnet/tx/$txid");
|
||||
case Coin.namecoin:
|
||||
return Uri.parse("https://chainz.cryptoid.info/nmc/tx.dws?$txid.htm");
|
||||
case Coin.bitcoincashTestnet:
|
||||
throw UnimplementedError("missing block explorer for epic cash");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,13 @@ class _CoinThemeColor {
|
|||
const _CoinThemeColor();
|
||||
|
||||
Color get bitcoin => const Color(0xFFFCC17B);
|
||||
Color get bitcoincash => const Color(0xFFFCC17B);
|
||||
Color get bitcoincash => const Color(0xFF7BCFB8);
|
||||
Color get firo => const Color(0xFFFF897A);
|
||||
Color get dogecoin => const Color(0xFFFFE079);
|
||||
Color get epicCash => const Color(0xFFC5C7CB);
|
||||
Color get monero => const Color(0xFFFF9E6B);
|
||||
Color get namecoin => const Color(0xFFFCC17B);
|
||||
Color get namecoin => const Color(0xFF91B1E1);
|
||||
Color get wownero => const Color(0xFFED80C1);
|
||||
|
||||
Color forCoin(Coin coin) {
|
||||
switch (coin) {
|
||||
|
@ -33,6 +34,8 @@ class _CoinThemeColor {
|
|||
return monero;
|
||||
case Coin.namecoin:
|
||||
return namecoin;
|
||||
// case Coin.wownero:
|
||||
// return wownero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart' as btc;
|
||||
import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart'
|
||||
as bch;
|
||||
import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart'
|
||||
as doge;
|
||||
import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart'
|
||||
as epic;
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart' as firo;
|
||||
import 'package:stackwallet/services/coins/monero/monero_wallet.dart' as xmr;
|
||||
import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart'
|
||||
as bch;
|
||||
import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart'
|
||||
as nmc;
|
||||
|
||||
|
@ -30,7 +30,7 @@ enum Coin {
|
|||
}
|
||||
|
||||
// remove firotestnet for now
|
||||
const int kTestNetCoinCount = 2;
|
||||
const int kTestNetCoinCount = 3;
|
||||
|
||||
extension CoinExt on Coin {
|
||||
String get prettyName {
|
||||
|
@ -52,7 +52,7 @@ extension CoinExt on Coin {
|
|||
case Coin.bitcoinTestNet:
|
||||
return "tBitcoin";
|
||||
case Coin.bitcoincashTestnet:
|
||||
return "tBitcoincash";
|
||||
return "tBitcoin Cash";
|
||||
case Coin.firoTestNet:
|
||||
return "tFiro";
|
||||
case Coin.dogecoinTestNet:
|
||||
|
@ -193,7 +193,7 @@ Coin coinFromPrettyName(String name) {
|
|||
return Coin.bitcoinTestNet;
|
||||
|
||||
case "Bitcoincash Testnet":
|
||||
case "tBitcoincash":
|
||||
case "tBitcoin Cash":
|
||||
case "Bitcoin Cash Testnet":
|
||||
return Coin.bitcoincashTestnet;
|
||||
case "Firo Testnet":
|
||||
|
|
|
@ -79,44 +79,46 @@ class WalletSheetCard extends ConsumerWidget {
|
|||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
manager.walletName,
|
||||
style: STextStyles.titleBold12,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: manager.totalBalance,
|
||||
builder: (builderContext, AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: snapshot.data!,
|
||||
locale: locale,
|
||||
decimalPlaces: 8,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle,
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading balance",
|
||||
"Loading balance.",
|
||||
"Loading balance..",
|
||||
"Loading balance..."
|
||||
],
|
||||
style: STextStyles.itemSubtitle,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
manager.walletName,
|
||||
style: STextStyles.titleBold12,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: manager.totalBalance,
|
||||
builder: (builderContext, AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: snapshot.data!,
|
||||
locale: locale,
|
||||
decimalPlaces: 8,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle,
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading balance",
|
||||
"Loading balance.",
|
||||
"Loading balance..",
|
||||
"Loading balance..."
|
||||
],
|
||||
style: STextStyles.itemSubtitle,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
21
pubspec.lock
21
pubspec.lock
|
@ -74,9 +74,11 @@ packages:
|
|||
bech32:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: bech32
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
path: "."
|
||||
ref: "22279d4bb24ed541b431acd269a1bc50af0f36a0"
|
||||
resolved-ref: "22279d4bb24ed541b431acd269a1bc50af0f36a0"
|
||||
url: "https://github.com/cypherstack/bech32.git"
|
||||
source: git
|
||||
version: "0.2.1"
|
||||
bip32:
|
||||
dependency: "direct main"
|
||||
|
@ -94,12 +96,21 @@ packages:
|
|||
url: "https://github.com/cypherstack/stack-bip39.git"
|
||||
source: git
|
||||
version: "1.0.6"
|
||||
bitbox:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: ea65073efbaf395a5557e8cd7bd72f195cd7eb11
|
||||
resolved-ref: ea65073efbaf395a5557e8cd7bd72f195cd7eb11
|
||||
url: "https://github.com/Quppy/bitbox-flutter.git"
|
||||
source: git
|
||||
version: "1.0.1"
|
||||
bitcoindart:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: a35968c2d2d900e77baa9f8b28c89b722c074039
|
||||
resolved-ref: a35968c2d2d900e77baa9f8b28c89b722c074039
|
||||
ref: "65eb920719c8f7895c5402a07497647e7fc4b346"
|
||||
resolved-ref: "65eb920719c8f7895c5402a07497647e7fc4b346"
|
||||
url: "https://github.com/cypherstack/bitcoindart.git"
|
||||
source: git
|
||||
version: "3.0.1"
|
||||
|
|
|
@ -11,7 +11,7 @@ description: Stack Wallet
|
|||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 1.4.42+56
|
||||
version: 1.4.43+58
|
||||
|
||||
environment:
|
||||
sdk: ">=2.17.0 <3.0.0"
|
||||
|
|
|
@ -28,7 +28,7 @@ import 'bitcoin_wallet_test_parameters.dart';
|
|||
void main() {
|
||||
group("bitcoin constants", () {
|
||||
test("bitcoin minimum confirmations", () async {
|
||||
expect(MINIMUM_CONFIRMATIONS, 2);
|
||||
expect(MINIMUM_CONFIRMATIONS, 1);
|
||||
});
|
||||
test("bitcoin dust limit", () async {
|
||||
expect(DUST_LIMIT, 294);
|
||||
|
|
|
@ -20,8 +20,6 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
|||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
|
||||
import 'dogecoin_history_sample_data.dart';
|
||||
import 'dogecoin_transaction_data_samples.dart';
|
||||
import 'dogecoin_utxo_sample_data.dart';
|
||||
import 'dogecoin_wallet_test.mocks.dart';
|
||||
import 'dogecoin_wallet_test_parameters.dart';
|
||||
|
||||
|
@ -1853,102 +1851,6 @@ void main() {
|
|||
// // verifyNoMoreInteractions(priceAPI);
|
||||
// // });
|
||||
|
||||
test("fullRescan succeeds", () async {
|
||||
when(client?.getServerFeatures()).thenAnswer((_) async => {
|
||||
"hosts": {},
|
||||
"pruning": null,
|
||||
"server_version": "Unit tests",
|
||||
"protocol_min": "1.4",
|
||||
"protocol_max": "1.4.2",
|
||||
"genesis_hash": GENESIS_HASH_MAINNET,
|
||||
"hash_function": "sha256",
|
||||
"services": []
|
||||
});
|
||||
when(client?.getBatchHistory(args: historyBatchArgs0))
|
||||
.thenAnswer((_) async => historyBatchResponse);
|
||||
when(client?.getBatchHistory(args: historyBatchArgs1))
|
||||
.thenAnswer((_) async => historyBatchResponse);
|
||||
when(cachedClient?.clearSharedTransactionCache(coin: Coin.dogecoin))
|
||||
.thenAnswer((realInvocation) async {});
|
||||
|
||||
final wallet = await Hive.openBox(testWalletId);
|
||||
|
||||
// restore so we have something to rescan
|
||||
await doge?.recoverFromMnemonic(
|
||||
mnemonic: TEST_MNEMONIC,
|
||||
maxUnusedAddressGap: 2,
|
||||
maxNumberOfIndexesToCheck: 1000,
|
||||
height: 4000);
|
||||
|
||||
// fetch valid wallet data
|
||||
final preReceivingAddressesP2PKH =
|
||||
await wallet.get('receivingAddressesP2PKH');
|
||||
final preChangeAddressesP2PKH = await wallet.get('changeAddressesP2PKH');
|
||||
final preReceivingIndexP2PKH = await wallet.get('receivingIndexP2PKH');
|
||||
final preChangeIndexP2PKH = await wallet.get('changeIndexP2PKH');
|
||||
final preUtxoData = await wallet.get('latest_utxo_model');
|
||||
final preReceiveDerivationsStringP2PKH = await secureStore?.read(
|
||||
key: "${testWalletId}_receiveDerivationsP2PKH");
|
||||
final preChangeDerivationsStringP2PKH = await secureStore?.read(
|
||||
key: "${testWalletId}_changeDerivationsP2PKH");
|
||||
|
||||
// destroy the data that the rescan will fix
|
||||
await wallet.put(
|
||||
'receivingAddressesP2PKH', ["some address", "some other address"]);
|
||||
await wallet
|
||||
.put('changeAddressesP2PKH', ["some address", "some other address"]);
|
||||
|
||||
await wallet.put('receivingIndexP2PKH', 123);
|
||||
await wallet.put('changeIndexP2PKH', 123);
|
||||
await secureStore?.write(
|
||||
key: "${testWalletId}_receiveDerivationsP2PKH", value: "{}");
|
||||
await secureStore?.write(
|
||||
key: "${testWalletId}_changeDerivationsP2PKH", value: "{}");
|
||||
|
||||
bool hasThrown = false;
|
||||
try {
|
||||
await doge?.fullRescan(2, 1000);
|
||||
} catch (_) {
|
||||
hasThrown = true;
|
||||
}
|
||||
expect(hasThrown, false);
|
||||
|
||||
// fetch wallet data again
|
||||
final receivingAddressesP2PKH =
|
||||
await wallet.get('receivingAddressesP2PKH');
|
||||
final changeAddressesP2PKH = await wallet.get('changeAddressesP2PKH');
|
||||
final receivingIndexP2PKH = await wallet.get('receivingIndexP2PKH');
|
||||
final changeIndexP2PKH = await wallet.get('changeIndexP2PKH');
|
||||
final utxoData = await wallet.get('latest_utxo_model');
|
||||
final receiveDerivationsStringP2PKH = await secureStore?.read(
|
||||
key: "${testWalletId}_receiveDerivationsP2PKH");
|
||||
final changeDerivationsStringP2PKH = await secureStore?.read(
|
||||
key: "${testWalletId}_changeDerivationsP2PKH");
|
||||
|
||||
expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH);
|
||||
expect(preChangeAddressesP2PKH, changeAddressesP2PKH);
|
||||
expect(preReceivingIndexP2PKH, receivingIndexP2PKH);
|
||||
expect(preChangeIndexP2PKH, changeIndexP2PKH);
|
||||
expect(preUtxoData, utxoData);
|
||||
expect(preReceiveDerivationsStringP2PKH, receiveDerivationsStringP2PKH);
|
||||
expect(preChangeDerivationsStringP2PKH, changeDerivationsStringP2PKH);
|
||||
|
||||
verify(client?.getServerFeatures()).called(1);
|
||||
verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2);
|
||||
verify(client?.getBatchHistory(args: historyBatchArgs1)).called(2);
|
||||
verify(cachedClient?.clearSharedTransactionCache(coin: Coin.dogecoin))
|
||||
.called(1);
|
||||
|
||||
expect(secureStore?.writes, 9);
|
||||
expect(secureStore?.reads, 12);
|
||||
expect(secureStore?.deletes, 2);
|
||||
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(tracker);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
});
|
||||
|
||||
test("get mnemonic list", () async {
|
||||
when(client?.getServerFeatures()).thenAnswer((_) async => {
|
||||
"hosts": {},
|
||||
|
@ -2118,7 +2020,19 @@ void main() {
|
|||
when(client?.getBatchHistory(args: historyBatchArgs1))
|
||||
.thenAnswer((_) async => historyBatchResponse);
|
||||
|
||||
final wallet = await Hive.openBox(testWalletId);
|
||||
when(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"c82d4ac9697408d423d59dc53267f6474bbd4c22c55fd42ba766e80c6068e7dc"
|
||||
]
|
||||
})).thenAnswer((realInvocation) async => {"0": []});
|
||||
|
||||
when(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"80badd62a8dd884cc7f61d962484564929340debb27f88fef270e553306a030c"
|
||||
]
|
||||
})).thenAnswer((realInvocation) async => {"0": []});
|
||||
|
||||
final wallet = await Hive.openBox<dynamic>(testWalletId);
|
||||
|
||||
bool hasThrown = false;
|
||||
try {
|
||||
|
@ -2135,6 +2049,16 @@ void main() {
|
|||
verify(client?.getServerFeatures()).called(1);
|
||||
verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1);
|
||||
verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1);
|
||||
verify(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"c82d4ac9697408d423d59dc53267f6474bbd4c22c55fd42ba766e80c6068e7dc"
|
||||
]
|
||||
})).called(1);
|
||||
verify(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"80badd62a8dd884cc7f61d962484564929340debb27f88fef270e553306a030c"
|
||||
]
|
||||
})).called(1);
|
||||
|
||||
expect(secureStore?.interactions, 6);
|
||||
expect(secureStore?.writes, 3);
|
||||
|
@ -2165,7 +2089,19 @@ void main() {
|
|||
when(cachedClient?.clearSharedTransactionCache(coin: Coin.dogecoin))
|
||||
.thenAnswer((realInvocation) async {});
|
||||
|
||||
final wallet = await Hive.openBox(testWalletId);
|
||||
when(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"c82d4ac9697408d423d59dc53267f6474bbd4c22c55fd42ba766e80c6068e7dc"
|
||||
]
|
||||
})).thenAnswer((realInvocation) async => {"0": []});
|
||||
|
||||
when(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"80badd62a8dd884cc7f61d962484564929340debb27f88fef270e553306a030c"
|
||||
]
|
||||
})).thenAnswer((realInvocation) async => {"0": []});
|
||||
|
||||
final wallet = await Hive.openBox<dynamic>(testWalletId);
|
||||
|
||||
// restore so we have something to rescan
|
||||
await doge?.recoverFromMnemonic(
|
||||
|
@ -2230,6 +2166,16 @@ void main() {
|
|||
verify(client?.getServerFeatures()).called(1);
|
||||
verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2);
|
||||
verify(client?.getBatchHistory(args: historyBatchArgs1)).called(2);
|
||||
verify(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"c82d4ac9697408d423d59dc53267f6474bbd4c22c55fd42ba766e80c6068e7dc"
|
||||
]
|
||||
})).called(2);
|
||||
verify(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"80badd62a8dd884cc7f61d962484564929340debb27f88fef270e553306a030c"
|
||||
]
|
||||
})).called(2);
|
||||
verify(cachedClient?.clearSharedTransactionCache(coin: Coin.dogecoin))
|
||||
.called(1);
|
||||
|
||||
|
@ -2259,6 +2205,18 @@ void main() {
|
|||
.thenAnswer((_) async => historyBatchResponse);
|
||||
when(client?.getBatchHistory(args: historyBatchArgs1))
|
||||
.thenAnswer((_) async => historyBatchResponse);
|
||||
|
||||
when(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"c82d4ac9697408d423d59dc53267f6474bbd4c22c55fd42ba766e80c6068e7dc"
|
||||
]
|
||||
})).thenAnswer((realInvocation) async => {"0": []});
|
||||
|
||||
when(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"80badd62a8dd884cc7f61d962484564929340debb27f88fef270e553306a030c"
|
||||
]
|
||||
})).thenAnswer((realInvocation) async => {"0": []});
|
||||
when(cachedClient?.clearSharedTransactionCache(coin: Coin.dogecoin))
|
||||
.thenAnswer((realInvocation) async {});
|
||||
|
||||
|
@ -2318,7 +2276,17 @@ void main() {
|
|||
|
||||
verify(client?.getServerFeatures()).called(1);
|
||||
verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2);
|
||||
verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1);
|
||||
verify(client?.getBatchHistory(args: historyBatchArgs1)).called(2);
|
||||
verify(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"c82d4ac9697408d423d59dc53267f6474bbd4c22c55fd42ba766e80c6068e7dc"
|
||||
]
|
||||
})).called(2);
|
||||
verify(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"80badd62a8dd884cc7f61d962484564929340debb27f88fef270e553306a030c"
|
||||
]
|
||||
})).called(1);
|
||||
verify(cachedClient?.clearSharedTransactionCache(coin: Coin.dogecoin))
|
||||
.called(1);
|
||||
|
||||
|
@ -2814,6 +2782,17 @@ void main() {
|
|||
.thenAnswer((_) async => historyBatchResponse);
|
||||
when(client?.getBatchHistory(args: historyBatchArgs1))
|
||||
.thenAnswer((_) async => historyBatchResponse);
|
||||
when(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"c82d4ac9697408d423d59dc53267f6474bbd4c22c55fd42ba766e80c6068e7dc"
|
||||
]
|
||||
})).thenAnswer((realInvocation) async => {"0": []});
|
||||
|
||||
when(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"80badd62a8dd884cc7f61d962484564929340debb27f88fef270e553306a030c"
|
||||
]
|
||||
})).thenAnswer((realInvocation) async => {"0": []});
|
||||
|
||||
final wallet = await Hive.openBox(testWalletId);
|
||||
|
||||
|
@ -2831,6 +2810,16 @@ void main() {
|
|||
verify(client?.getServerFeatures()).called(1);
|
||||
verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1);
|
||||
verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1);
|
||||
verify(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"c82d4ac9697408d423d59dc53267f6474bbd4c22c55fd42ba766e80c6068e7dc"
|
||||
]
|
||||
})).called(1);
|
||||
verify(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"80badd62a8dd884cc7f61d962484564929340debb27f88fef270e553306a030c"
|
||||
]
|
||||
})).called(1);
|
||||
|
||||
expect(secureStore?.interactions, 6);
|
||||
expect(secureStore?.writes, 3);
|
||||
|
@ -2859,6 +2848,17 @@ void main() {
|
|||
.thenAnswer((_) async => historyBatchResponse);
|
||||
when(client?.getBatchHistory(args: historyBatchArgs1))
|
||||
.thenAnswer((_) async => historyBatchResponse);
|
||||
when(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"c82d4ac9697408d423d59dc53267f6474bbd4c22c55fd42ba766e80c6068e7dc"
|
||||
]
|
||||
})).thenAnswer((realInvocation) async => {"0": []});
|
||||
|
||||
when(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"80badd62a8dd884cc7f61d962484564929340debb27f88fef270e553306a030c"
|
||||
]
|
||||
})).thenAnswer((realInvocation) async => {"0": []});
|
||||
when(client?.getHistory(scripthash: anyNamed("scripthash")))
|
||||
.thenThrow(Exception("some exception"));
|
||||
|
||||
|
@ -2876,6 +2876,16 @@ void main() {
|
|||
verify(client?.getServerFeatures()).called(1);
|
||||
verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1);
|
||||
verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1);
|
||||
verify(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"c82d4ac9697408d423d59dc53267f6474bbd4c22c55fd42ba766e80c6068e7dc"
|
||||
]
|
||||
})).called(1);
|
||||
verify(client?.getBatchHistory(args: {
|
||||
"0": [
|
||||
"80badd62a8dd884cc7f61d962484564929340debb27f88fef270e553306a030c"
|
||||
]
|
||||
})).called(1);
|
||||
verify(client?.getBlockHeadTip()).called(1);
|
||||
verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(1);
|
||||
|
||||
|
|
Loading…
Reference in a new issue