multi: Add initial decred screens. (#1165)

Use a mock libwallet for now.
This commit is contained in:
JoeGruffins 2023-12-22 11:59:02 +00:00 committed by JoeGruff
parent 3e93a5ecb8
commit 76283cd82e
53 changed files with 1863 additions and 3 deletions

1
.gitignore vendored
View file

@ -137,6 +137,7 @@ lib/polygon/polygon.dart
lib/solana/solana.dart
lib/tron/tron.dart
lib/wownero/wownero.dart
lib/decred/decred.dart
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_180.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_120.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
assets/images/decred.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -27,6 +27,7 @@ class AmountConverter {
case CryptoCurrency.btc:
case CryptoCurrency.bch:
case CryptoCurrency.ltc:
case CryptoCurrency.dcr:
return _bitcoinAmountToString(amount);
case CryptoCurrency.xhv:
case CryptoCurrency.xag:

View file

@ -30,6 +30,8 @@ CryptoCurrency currencyForWalletType(WalletType type, {bool? isTestnet}) {
return CryptoCurrency.trx;
case WalletType.wownero:
return CryptoCurrency.wow;
case WalletType.decred:
return CryptoCurrency.dcr;
case WalletType.none:
throw Exception(
'Unexpected wallet type: ${type.toString()} for CryptoCurrency currencyForWalletType');

View file

@ -101,6 +101,8 @@ class Node extends HiveObject with Keyable {
case WalletType.tron:
return Uri.parse(
"http${isSSL ? "s" : ""}://$uriRaw${path!.startsWith("/") ? path : "/$path"}");
case WalletType.decred:
return Uri.http(uriRaw, '');
case WalletType.none:
throw Exception('Unexpected type ${type.toString()} for Node uri');
}
@ -160,6 +162,8 @@ class Node extends HiveObject with Keyable {
case WalletType.solana:
case WalletType.tron:
return requestElectrumServer();
case WalletType.decred:
return requestDecredNode();
case WalletType.none:
return false;
}
@ -284,3 +288,7 @@ class Node extends HiveObject with Keyable {
}
}
}
Future<bool> requestDecredNode() async {
return true;
}

View file

@ -16,6 +16,7 @@ const walletTypes = [
WalletType.polygon,
WalletType.solana,
WalletType.tron,
WalletType.decred,
];
@HiveType(typeId: WALLET_TYPE_TYPE_ID)
@ -58,6 +59,9 @@ enum WalletType {
@HiveField(12)
wownero,
@HiveField(13)
decred
}
int serializeToInt(WalletType type) {
@ -86,6 +90,8 @@ int serializeToInt(WalletType type) {
return 10;
case WalletType.wownero:
return 11;
case WalletType.decred:
return 12;
case WalletType.none:
return -1;
}
@ -117,6 +123,8 @@ WalletType deserializeFromInt(int raw) {
return WalletType.tron;
case 11:
return WalletType.wownero;
case 12:
return WalletType.decred;
default:
throw Exception('Unexpected token: $raw for WalletType deserializeFromInt');
}
@ -148,6 +156,8 @@ String walletTypeToString(WalletType type) {
return 'Tron';
case WalletType.wownero:
return 'Wownero';
case WalletType.decred:
return 'Decred';
case WalletType.none:
return '';
}
@ -179,6 +189,8 @@ String walletTypeToDisplayName(WalletType type) {
return 'Tron (TRX)';
case WalletType.wownero:
return 'Wownero (WOW)';
case WalletType.decred:
return 'Decred (DCR)';
case WalletType.none:
return '';
}
@ -213,6 +225,8 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type, {bool isTestnet = fal
return CryptoCurrency.trx;
case WalletType.wownero:
return CryptoCurrency.wow;
case WalletType.decred:
return CryptoCurrency.dcr;
case WalletType.none:
throw Exception(
'Unexpected wallet type: ${type.toString()} for CryptoCurrency walletTypeToCryptoCurrency');

0
cw_decred/.gitignore vendored Normal file
View file

10
cw_decred/.metadata Normal file
View file

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: b1395592de68cc8ac4522094ae59956dd21a91db
channel: stable
project_type: package

3
cw_decred/CHANGELOG.md Normal file
View file

@ -0,0 +1,3 @@
## [0.0.1] - TODO: Add release date.
* TODO: Describe initial release.

1
cw_decred/LICENSE Normal file
View file

@ -0,0 +1 @@
TODO: Add your license here.

3
cw_decred/README.md Normal file
View file

@ -0,0 +1,3 @@
# cw_decred
TODO: Fill this out.

View file

@ -0,0 +1,26 @@
import 'package:intl/intl.dart';
import 'package:cw_core/crypto_amount_format.dart';
const decredAmountLength = 8;
const decredAmountDivider = 100000000;
final decredAmountFormat = NumberFormat()
..maximumFractionDigits = decredAmountLength
..minimumFractionDigits = 1;
String decredAmountToString({required int amount}) => decredAmountFormat
.format(cryptoAmountToDouble(amount: amount, divider: decredAmountDivider));
double decredAmountToDouble({required int amount}) =>
cryptoAmountToDouble(amount: amount, divider: decredAmountDivider);
int stringDoubleToDecredAmount(String amount) {
int result = 0;
try {
result = (double.parse(amount) * decredAmountDivider).round();
} catch (e) {
result = 0;
}
return result;
}

View file

@ -0,0 +1,127 @@
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/unspent_transaction_output.dart';
import 'package:cw_decred/balance.dart';
import 'package:cw_decred/pending_transaction.dart';
import 'package:cw_decred/transaction_info.dart';
import 'package:cw_core/transaction_direction.dart';
import 'dart:typed_data';
import 'dart:io';
// Will it work if none of these are async functions?
class SPVWallet {
SPVWallet();
SPVWallet create(Uint8List seed, String password, WalletInfo walletInfo) {
return SPVWallet();
}
SPVWallet load(String password, String name, WalletInfo walletInfo) {
return SPVWallet();
}
DecredBalance balance() {
return DecredBalance(
confirmed: 777,
unconfirmed: 111,
);
}
int feeRate(int priority) {
return 1000;
}
int calculateEstimatedFeeWithFeeRate(int feeRate, int amount) {
// Ideally we create a tx with wallet going to this amount and just return
// the fee we get back.
return 123000;
}
void close() {}
DecredPendingTransaction createTransaction(Object credentials) {
return DecredPendingTransaction(
spv: this,
txid:
"3cbf3eb9523fd04e96dbaf98cdbd21779222cc8855ece8700494662ae7578e02",
amount: 12345678,
fee: 1234,
rawHex: "baadbeef");
}
void rescan(int height) {
sleep(Duration(seconds: 10));
}
void startSync() {
sleep(Duration(seconds: 5));
}
SyncStatus syncStatus() {
return SyncedSyncStatus();
}
int height() {
return 400;
}
Map<String, DecredTransactionInfo> transactions() {
final txInfo = DecredTransactionInfo(
id: "3cbf3eb9523fd04e96dbaf98cdbd21779222cc8855ece8700494662ae7578e02",
amount: 1234567,
fee: 123,
direction: TransactionDirection.outgoing,
isPending: true,
date: DateTime.now(),
height: 0,
confirmations: 0,
to: "DsT4qJPPaYEuQRimfgvSKxKH3paysn1x3Nt",
);
return {
"3cbf3eb9523fd04e96dbaf98cdbd21779222cc8855ece8700494662ae7578e02": txInfo
};
}
String newAddress() {
// external
return "DsT4qJPPaYEuQRimfgvSKxKH3paysn1x3Nt";
}
List<String> addresses() {
return [
"DsT4qJPPaYEuQRimfgvSKxKH3paysn1x3Nt",
"DsVZGfGpd7WVffBZ5wbFZEHLV3FHNmXs9Az"
];
}
List<Unspent> unspents() {
return [
Unspent(
"DsT4qJPPaYEuQRimfgvSKxKH3paysn1x3Nt",
"3cbf3eb9523fd04e96dbaf98cdbd21779222cc8855ece8700494662ae7578e02",
1234567,
0,
null)
];
}
void changePassword(String newPW) {}
void sendRawTransaction(String rawHex) {}
String signMessage(String message, String? address) {
return "abababababababab";
}
}
Uint8List mnemonicToSeedBytes(String mnemonic) {
return Uint8List(32);
}
String generateMnemonic() {
return "maid upper strategy dove theory dream material cruel season best napkin ethics biology top episode rough hotel flight video target organ six disagree verify maid upper strategy dove theory dream material cruel season best napkin ethics biology top episode rough hotel flight video target organ six disagree verify";
}
bool validateMnemonic(String mnemonic) {
return true;
}

View file

@ -0,0 +1,18 @@
import 'package:cw_decred/amount_format.dart';
import 'package:cw_core/balance.dart';
class DecredBalance extends Balance {
const DecredBalance({required this.confirmed, required this.unconfirmed})
: super(confirmed, unconfirmed);
final int confirmed;
final int unconfirmed;
@override
String get formattedAvailableBalance =>
decredAmountToString(amount: confirmed);
@override
String get formattedAdditionalBalance =>
decredAmountToString(amount: unconfirmed);
}

View file

@ -0,0 +1,28 @@
List<String> wordList() {
return [
"maid",
"upper",
"strategy",
"dove",
"theory",
"dream",
"material",
"cruel",
"season",
"best",
"napkin",
"ethics",
"biology",
"top",
"episode",
"rough",
"hotel",
"flight",
"video",
"target",
"organ",
"six",
"disagree",
"verify"
];
}

View file

@ -0,0 +1,5 @@
class DecredMnemonicIsIncorrectException implements Exception {
@override
String toString() =>
'Decred mnemonic has incorrect format. Mnemonic should contain 12 or 24 words separated by space.';
}

View file

@ -0,0 +1,35 @@
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_decred/amount_format.dart';
import 'package:cw_decred/api/dcrlibwallet.dart';
class DecredPendingTransaction with PendingTransaction {
DecredPendingTransaction(
{required this.spv,
required this.txid,
required this.amount,
required this.fee,
required this.rawHex});
final SPVWallet spv;
final int amount;
final int fee;
final String txid;
final String rawHex;
@override
String get id => txid;
@override
String get amountFormatted => decredAmountToString(amount: amount);
@override
String get feeFormatted => decredAmountToString(amount: fee);
@override
String get hex => rawHex;
@override
Future<void> commit() async {
this.spv.sendRawTransaction(this.rawHex);
}
}

View file

@ -0,0 +1,11 @@
import 'package:cw_decred/transaction_priority.dart';
import 'package:cw_core/output_info.dart';
class DecredTransactionCredentials {
DecredTransactionCredentials(this.outputs,
{required this.priority, this.feeRate});
final List<OutputInfo> outputs;
final DecredTransactionPriority? priority;
final int? feeRate;
}

View file

@ -0,0 +1,28 @@
import 'package:mobx/mobx.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/transaction_history.dart';
// NOTE: Methods currently not used.
class DecredTransactionHistory extends TransactionHistoryBase<TransactionInfo> {
DecredTransactionHistory() {
transactions = ObservableMap<String, TransactionInfo>();
}
Future<void> init() async {}
@override
void addOne(TransactionInfo transaction) =>
transactions[transaction.id] = transaction;
@override
void addMany(Map<String, TransactionInfo> transactions) =>
this.transactions.addAll(transactions);
@override
Future<void> save() async {}
Future<void> changePassword(String password) async {}
void _update(TransactionInfo transaction) =>
transactions[transaction.id] = transaction;
}

View file

@ -0,0 +1,45 @@
import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/format_amount.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cw_decred/amount_format.dart';
class DecredTransactionInfo extends TransactionInfo {
DecredTransactionInfo({
required String id,
required int amount,
required int fee,
required TransactionDirection direction,
required bool isPending,
required DateTime date,
required int height,
required int confirmations,
required String to,
}) {
this.id = id;
this.amount = amount;
this.fee = fee;
this.height = height;
this.direction = direction;
this.date = date;
this.isPending = isPending;
this.confirmations = confirmations;
this.to = to;
}
String? _fiatAmount;
@override
String amountFormatted() =>
'${formatAmount(decredAmountToString(amount: amount))} ${walletTypeToCryptoCurrency(WalletType.decred).title}';
@override
String? feeFormatted() =>
'${formatAmount(decredAmountToString(amount: amount))} ${walletTypeToCryptoCurrency(WalletType.decred).title}';
@override
String fiatAmount() => _fiatAmount ?? '';
@override
void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount);
}

View file

@ -0,0 +1,54 @@
import 'package:cw_core/transaction_priority.dart';
class DecredTransactionPriority extends TransactionPriority {
const DecredTransactionPriority({required String title, required int raw})
: super(title: title, raw: raw);
static const List<DecredTransactionPriority> all = [fast, medium, slow];
static const DecredTransactionPriority slow =
DecredTransactionPriority(title: 'Slow', raw: 0);
static const DecredTransactionPriority medium =
DecredTransactionPriority(title: 'Medium', raw: 1);
static const DecredTransactionPriority fast =
DecredTransactionPriority(title: 'Fast', raw: 2);
static DecredTransactionPriority deserialize({required int raw}) {
switch (raw) {
case 0:
return slow;
case 1:
return medium;
case 2:
return fast;
default:
throw Exception(
'Unexpected token: $raw for DecredTransactionPriority deserialize');
}
}
String get units => 'atom';
@override
String toString() {
var label = '';
switch (this) {
case DecredTransactionPriority.slow:
label =
'Slow ~24hrs'; // '${S.current.transaction_priority_slow} ~24hrs';
break;
case DecredTransactionPriority.medium:
label = 'Medium'; // S.current.transaction_priority_medium;
break;
case DecredTransactionPriority.fast:
label = 'Fast'; // S.current.transaction_priority_fast;
break;
default:
break;
}
return label;
}
String labelWithRate(int rate) => '${toString()} ($rate ${units}/byte)';
}

212
cw_decred/lib/wallet.dart Normal file
View file

@ -0,0 +1,212 @@
import 'package:cw_decred/transaction_history.dart';
import 'package:cw_decred/wallet_addresses.dart';
import 'package:cw_decred/transaction_priority.dart';
import 'package:cw_decred/api/dcrlibwallet.dart';
import 'package:cw_decred/balance.dart';
import 'package:cw_decred/transaction_info.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:mobx/mobx.dart';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/unspent_transaction_output.dart';
part 'wallet.g.dart';
class DecredWallet = DecredWalletBase with _$DecredWallet;
abstract class DecredWalletBase extends WalletBase<DecredBalance,
DecredTransactionHistory, DecredTransactionInfo> with Store {
DecredWalletBase(SPVWallet spv, WalletInfo walletInfo)
: this.spv = spv,
balance = ObservableMap<CryptoCurrency, DecredBalance>.of(
{CryptoCurrency.dcr: spv.balance()}),
syncStatus = NotConnectedSyncStatus(),
super(walletInfo) {
transactionHistory = DecredTransactionHistory();
walletAddresses = DecredWalletAddresses(walletInfo, spv);
}
final SPVWallet spv;
static Future<DecredWallet> create(
{required String mnemonic,
required String password,
required WalletInfo walletInfo}) async {
final seed = mnemonicToSeedBytes(mnemonic);
final spv = SPVWallet().create(seed, password, walletInfo);
final wallet = DecredWallet(spv, walletInfo);
return wallet;
}
static Future<DecredWallet> open(
{required String password,
required String name,
required WalletInfo walletInfo}) async {
final spv = SPVWallet().load(name, password, walletInfo);
final wallet = DecredWallet(spv, walletInfo);
return wallet;
}
// TODO: Set up a way to change the balance and sync status when dcrlibwallet
// changes. Long polling probably?
@override
@observable
late ObservableMap<CryptoCurrency, DecredBalance> balance;
@override
@observable
SyncStatus syncStatus;
// @override
// set syncStatus(SyncStatus status);
@override
String? get seed {
// throw UnimplementedError();
return "";
}
// @override
// String? get privateKey => null;
@override
Object get keys {
// throw UnimplementedError();
return {};
}
@override
late DecredWalletAddresses walletAddresses;
// @override
// set isEnabledAutoGenerateSubaddress(bool value) {}
// @override
// bool get isEnabledAutoGenerateSubaddress => false;
@override
Future<void> connectToNode({required Node node}) async {
//throw UnimplementedError();
}
@action
@override
Future<void> startSync() async {
try {
this.spv.startSync();
syncStatus = this.spv.syncStatus();
} catch (e, stacktrace) {
print(stacktrace);
print(e.toString());
syncStatus = FailedSyncStatus();
}
}
@override
Future<PendingTransaction> createTransaction(Object credentials) async {
return this.spv.createTransaction(credentials);
}
int feeRate(TransactionPriority priority) {
try {
return this.spv.feeRate(priority.raw);
} catch (_) {
return 0;
}
}
@override
int calculateEstimatedFee(TransactionPriority priority, int? amount) {
if (priority is DecredTransactionPriority) {
return this.spv.calculateEstimatedFeeWithFeeRate(
this.spv.feeRate(priority.raw), amount ?? 0);
}
return 0;
}
@override
Future<Map<String, DecredTransactionInfo>> fetchTransactions() async {
return this.spv.transactions();
}
@override
Future<void> save() async {}
@override
Future<void> rescan({required int height}) async {
return spv.rescan(height);
}
@override
void close() {
this.spv.close();
}
@override
Future<void> changePassword(String password) async {
return this.spv.changePassword(password);
}
@override
String get password {
// throw UnimplementedError();
return "";
}
@override
Future<void>? updateBalance() async {
balance[CryptoCurrency.dcr] = this.spv.balance();
}
@override
void setExceptionHandler(void Function(FlutterErrorDetails) onError) =>
onError;
Future<void> renameWalletFiles(String newWalletName) async {
final currentWalletPath =
await pathForWallet(name: walletInfo.name, type: type);
final currentWalletFile = File(currentWalletPath);
final currentDirPath =
await pathForWalletDir(name: walletInfo.name, type: type);
// TODO: Stop the wallet, wait, and restart after.
// Copies current wallet files into new wallet name's dir and files
if (currentWalletFile.existsSync()) {
final newWalletPath =
await pathForWallet(name: newWalletName, type: type);
await currentWalletFile.copy(newWalletPath);
}
// Delete old name's dir and files
await Directory(currentDirPath).delete(recursive: true);
}
@override
String signMessage(String message, {String? address = null}) {
return this.spv.signMessage(message, address);
}
List<Unspent> unspents() {
return this.spv.unspents();
}
@override
Future<bool> verifyMessage(String message, String signature, {String? address = null}) {
return true;
}
@override
String get password {
return "";
}
}

View file

@ -0,0 +1,36 @@
import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_decred/api/dcrlibwallet.dart';
class DecredWalletAddresses extends WalletAddresses {
DecredWalletAddresses(WalletInfo walletInfo, SPVWallet spv)
: this.spv = spv,
super(walletInfo);
final SPVWallet spv;
@override
String get address {
return this.spv.newAddress();
}
String generateNewAddress() {
return this.spv.newAddress();
}
List<String> addresses() {
return this.spv.addresses();
}
@override
set address(String addr) {}
@override
Future<void> init() async {}
@override
Future<void> updateAddressesInBox() async {}
@override
Future<void> saveAddressesInBox() async {}
}

View file

@ -0,0 +1,44 @@
import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/hardware/hardware_account_data.dart';
class DecredNewWalletCredentials extends WalletCredentials {
DecredNewWalletCredentials({required String name, WalletInfo? walletInfo})
: super(name: name, walletInfo: walletInfo);
}
class DecredRestoreWalletFromSeedCredentials extends WalletCredentials {
DecredRestoreWalletFromSeedCredentials(
{required String name,
required String password,
required this.mnemonic,
WalletInfo? walletInfo})
: super(name: name, password: password, walletInfo: walletInfo);
final String mnemonic;
}
class DecredRestoreWalletFromWIFCredentials extends WalletCredentials {
DecredRestoreWalletFromWIFCredentials(
{required String name,
required String password,
required this.wif,
WalletInfo? walletInfo})
: t = throw UnimplementedError(), // TODO: Maybe can be used to create watching only wallets?
super(name: name, password: password, walletInfo: walletInfo);
final String wif;
final void t;
}
class DecredRestoreWalletFromHardwareCredentials extends WalletCredentials {
DecredRestoreWalletFromHardwareCredentials(
{required String name,
required this.hwAccountData,
WalletInfo? walletInfo})
: t = throw UnimplementedError(),
super(name: name, walletInfo: walletInfo);
final HardwareAccountData hwAccountData;
final void t;
}

View file

@ -0,0 +1,99 @@
import 'dart:io';
import 'package:cw_decred/mnemonic_is_incorrect_exception.dart';
import 'package:cw_decred/wallet_creation_credentials.dart';
import 'package:cw_decred/wallet.dart';
import 'package:cw_decred/api/dcrlibwallet.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:hive/hive.dart';
import 'package:collection/collection.dart';
class DecredWalletService extends WalletService<
DecredNewWalletCredentials,
DecredRestoreWalletFromSeedCredentials,
DecredRestoreWalletFromPubkeyCredentials,
DecredRestoreWalletFromHardwareCredentials> {
DecredWalletService(this.walletInfoSource);
final Box<WalletInfo> walletInfoSource;
@override
WalletType getType() => WalletType.decred;
@override
Future<DecredWallet> create(DecredNewWalletCredentials credentials,
{bool? isTestnet}) async {
return await DecredWalletBase.create(
mnemonic: generateMnemonic(),
password: credentials.password!,
walletInfo: credentials.walletInfo!);
}
@override
Future<bool> isWalletExit(String name) async =>
File(await pathForWallet(name: name, type: getType())).existsSync();
@override
Future<DecredWallet> openWallet(String name, String password) async {
final walletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(name, getType()))!;
final wallet = await DecredWalletBase.open(
password: password, name: name, walletInfo: walletInfo);
return wallet;
}
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType()))
.delete(recursive: true);
final walletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(wallet, getType()))!;
await walletInfoSource.delete(walletInfo.key);
}
@override
Future<void> rename(
String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(currentName, getType()))!;
final currentWallet = await DecredWalletBase.open(
password: password, name: currentName, walletInfo: currentWalletInfo);
await currentWallet.renameWalletFiles(newName);
final newWalletInfo = currentWalletInfo;
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
}
@override
Future<DecredWallet> restoreFromSeed(
DecredRestoreWalletFromSeedCredentials credentials,
{bool? isTestnet}) async {
if (!validateMnemonic(credentials.mnemonic)) {
throw DecredMnemonicIsIncorrectException();
}
final wallet = await DecredWalletBase.create(
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!);
return wallet;
}
@override
Future<DecredWallet> restoreFromKeys(
DecredRestoreWalletFromWIFCredentials credentials,
{bool? isTestnet}) async =>
throw UnimplementedError();
@override
Future<DecredWallet> restoreFromHardwareWallet(
DecredRestoreWalletFromHardwareCredentials credentials) async =>
throw UnimplementedError();
}

724
cw_decred/pubspec.lock Normal file
View file

@ -0,0 +1,724 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8"
url: "https://pub.dev"
source: hosted
version: "47.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80"
url: "https://pub.dev"
source: hosted
version: "4.7.0"
args:
dependency: transitive
description:
name: args
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
url: "https://pub.dev"
source: hosted
version: "2.4.2"
asn1lib:
dependency: transitive
description:
name: asn1lib
sha256: "21afe4333076c02877d14f4a89df111e658a6d466cbfc802eb705eb91bd5adfd"
url: "https://pub.dev"
source: hosted
version: "1.5.0"
async:
dependency: transitive
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.11.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
build:
dependency: transitive
description:
name: build
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
build_config:
dependency: transitive
description:
name: build_config
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
url: "https://pub.dev"
source: hosted
version: "1.1.1"
build_daemon:
dependency: transitive
description:
name: build_daemon
sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65"
url: "https://pub.dev"
source: hosted
version: "4.0.0"
build_resolvers:
dependency: "direct dev"
description:
name: build_resolvers
sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6"
url: "https://pub.dev"
source: hosted
version: "2.0.10"
build_runner:
dependency: "direct dev"
description:
name: build_runner
sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b"
url: "https://pub.dev"
source: hosted
version: "2.4.6"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41"
url: "https://pub.dev"
source: hosted
version: "7.2.10"
built_collection:
dependency: transitive
description:
name: built_collection
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
url: "https://pub.dev"
source: hosted
version: "5.1.1"
built_value:
dependency: transitive
description:
name: built_value
sha256: "723b4021e903217dfc445ec4cf5b42e27975aece1fc4ebbc1ca6329c2d9fb54e"
url: "https://pub.dev"
source: hosted
version: "8.7.0"
characters:
dependency: transitive
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
url: "https://pub.dev"
source: hosted
version: "2.0.3"
clock:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.1"
code_builder:
dependency: transitive
description:
name: code_builder
sha256: "1be9be30396d7e4c0db42c35ea6ccd7cc6a1e19916b5dc64d6ac216b5544d677"
url: "https://pub.dev"
source: hosted
version: "4.7.0"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.18.0"
convert:
dependency: transitive
description:
name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
crypto:
dependency: transitive
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
version: "3.0.3"
cw_core:
dependency: "direct main"
description:
path: "../cw_core"
relative: true
source: path
version: "0.0.1"
dart_style:
dependency: transitive
description:
name: dart_style
sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4"
url: "https://pub.dev"
source: hosted
version: "2.2.4"
encrypt:
dependency: transitive
description:
name: encrypt
sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
url: "https://pub.dev"
source: hosted
version: "5.0.3"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
file:
dependency: transitive
description:
name: file
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
url: "https://pub.dev"
source: hosted
version: "6.1.4"
fixnum:
dependency: transitive
description:
name: fixnum
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_mobx:
dependency: transitive
description:
name: flutter_mobx
sha256: "2ba0aa5a42811eaaeff2e35626689cf2b8a3869907d0e8889c914f2c95d8fd76"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
glob:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
graphs:
dependency: transitive
description:
name: graphs
sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19
url: "https://pub.dev"
source: hosted
version: "2.3.1"
hive:
dependency: transitive
description:
name: hive
sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
url: "https://pub.dev"
source: hosted
version: "2.2.3"
hive_generator:
dependency: "direct dev"
description:
name: hive_generator
sha256: "81fd20125cb2ce8fd23623d7744ffbaf653aae93706c9bd3bf7019ea0ace3938"
url: "https://pub.dev"
source: hosted
version: "1.1.3"
http:
dependency: transitive
description:
name: http
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
url: "https://pub.dev"
source: hosted
version: "3.2.1"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
intl:
dependency: transitive
description:
name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev"
source: hosted
version: "0.18.1"
io:
dependency: transitive
description:
name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
js:
dependency: transitive
description:
name: js
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev"
source: hosted
version: "0.6.7"
json_annotation:
dependency: transitive
description:
name: json_annotation
sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
url: "https://pub.dev"
source: hosted
version: "4.8.1"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
url: "https://pub.dev"
source: hosted
version: "10.0.0"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
url: "https://pub.dev"
source: hosted
version: "2.0.1"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
url: "https://pub.dev"
source: hosted
version: "2.0.1"
logging:
dependency: transitive
description:
name: logging
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev"
source: hosted
version: "0.8.0"
meta:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
url: "https://pub.dev"
source: hosted
version: "1.11.0"
mime:
dependency: transitive
description:
name: mime
sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
url: "https://pub.dev"
source: hosted
version: "1.0.4"
mobx:
dependency: transitive
description:
name: mobx
sha256: "42ae7277ec5c36fa5ce02aa14551065babce3c38a35947330144ff47bc775c75"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
mobx_codegen:
dependency: "direct dev"
description:
name: mobx_codegen
sha256: d4beb9cea4b7b014321235f8fdc7c2193ee0fe1d1198e9da7403f8bc85c4407c
url: "https://pub.dev"
source: hosted
version: "2.3.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
package_config:
dependency: transitive
description:
name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
path:
dependency: transitive
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
path_provider:
dependency: transitive
description:
name: path_provider
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
url: "https://pub.dev"
source: hosted
version: "2.1.1"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
url: "https://pub.dev"
source: hosted
version: "2.3.1"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
platform:
dependency: transitive
description:
name: platform
sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
url: "https://pub.dev"
source: hosted
version: "2.1.6"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
url: "https://pub.dev"
source: hosted
version: "3.7.3"
pool:
dependency: transitive
description:
name: pool
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
url: "https://pub.dev"
source: hosted
version: "1.5.1"
provider:
dependency: transitive
description:
name: provider
sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
url: "https://pub.dev"
source: hosted
version: "6.0.5"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367
url: "https://pub.dev"
source: hosted
version: "1.2.3"
shelf:
dependency: transitive
description:
name: shelf
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
url: "https://pub.dev"
source: hosted
version: "1.4.1"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_gen:
dependency: transitive
description:
name: source_gen
sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d"
url: "https://pub.dev"
source: hosted
version: "1.2.6"
source_helper:
dependency: transitive
description:
name: source_helper
sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f"
url: "https://pub.dev"
source: hosted
version: "1.3.3"
source_span:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.2"
stream_transform:
dependency: transitive
description:
name: stream_transform
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
url: "https://pub.dev"
source: hosted
version: "0.6.1"
timing:
dependency: transitive
description:
name: timing
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.2"
unorm_dart:
dependency: transitive
description:
name: unorm_dart
sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b"
url: "https://pub.dev"
source: hosted
version: "0.3.0"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
url: "https://pub.dev"
source: hosted
version: "13.0.0"
watcher:
dependency: transitive
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
url: "https://pub.dev"
source: hosted
version: "2.4.0"
win32:
dependency: transitive
description:
name: win32
sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3"
url: "https://pub.dev"
source: hosted
version: "5.0.9"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
url: "https://pub.dev"
source: hosted
version: "1.0.3"
yaml:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.2.0-0 <4.0.0"
flutter: ">=3.7.0"

24
cw_decred/pubspec.yaml Normal file
View file

@ -0,0 +1,24 @@
name: cw_decred
description: A new Flutter package project.
version: 0.0.1
publish_to: none
author: Cake Wallet
homepage: https://cakewallet.com
environment:
sdk: ">=2.17.5 <3.0.0"
flutter: ">=1.20.0"
dependencies:
flutter:
sdk: flutter
cw_core:
path: ../cw_core
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^2.1.11
build_resolvers: ^2.0.9
mobx_codegen: ^2.0.7
hive_generator: ^1.1.3

View file

@ -89,6 +89,7 @@ class WalletCreationService {
case WalletType.haven:
case WalletType.nano:
case WalletType.banano:
case WalletType.decred:
return false;
}
}

105
lib/decred/cw_decred.dart Normal file
View file

@ -0,0 +1,105 @@
part of 'decred.dart';
class CWDecred extends Decred {
@override
TransactionPriority getMediumTransactionPriority() =>
DecredTransactionPriority.medium;
@override
WalletCredentials createDecredRestoreWalletFromSeedCredentials(
{required String name,
required String mnemonic,
required String password}) =>
DecredRestoreWalletFromSeedCredentials(
name: name, mnemonic: mnemonic, password: password);
@override
WalletCredentials createDecredNewWalletCredentials(
{required String name, WalletInfo? walletInfo}) =>
DecredNewWalletCredentials(name: name, walletInfo: walletInfo);
@override
List<String> getWordList() => wordList();
@override
List<TransactionPriority> getTransactionPriorities() =>
DecredTransactionPriority.all;
@override
TransactionPriority deserializeDecredTransactionPriority(int raw) =>
DecredTransactionPriority.deserialize(raw: raw);
@override
int getFeeRate(Object wallet, TransactionPriority priority) {
final decredWallet = wallet as DecredWallet;
return decredWallet.feeRate(priority);
}
@override
Future<void> generateNewAddress(Object wallet) async {
final decredWallet = wallet as DecredWallet;
await decredWallet.walletAddresses.generateNewAddress();
}
@override
Object createDecredTransactionCredentials(
List<Output> outputs, TransactionPriority priority) =>
DecredTransactionCredentials(
outputs
.map((out) => OutputInfo(
fiatAmount: out.fiatAmount,
cryptoAmount: out.cryptoAmount,
address: out.address,
note: out.note,
sendAll: out.sendAll,
extractedAddress: out.extractedAddress,
isParsedAddress: out.isParsedAddress,
formattedCryptoAmount: out.formattedCryptoAmount))
.toList(),
priority:
priority != null ? priority as DecredTransactionPriority : null);
@override
List<String> getAddresses(Object wallet) {
final decredWallet = wallet as DecredWallet;
return decredWallet.walletAddresses.addresses();
}
@override
String getAddress(Object wallet) {
final decredWallet = wallet as DecredWallet;
return decredWallet.walletAddresses.address;
}
@override
String formatterDecredAmountToString({required int amount}) =>
decredAmountToString(amount: amount);
@override
double formatterDecredAmountToDouble({required int amount}) =>
decredAmountToDouble(amount: amount);
@override
int formatterStringDoubleToDecredAmount(String amount) =>
stringDoubleToDecredAmount(amount);
@override
List<Unspent> getUnspents(Object wallet) {
final decredWallet = wallet as DecredWallet;
return decredWallet.unspents();
}
void updateUnspents(Object wallet) async {}
WalletService createDecredWalletService(Box<WalletInfo> walletInfoSource) {
return DecredWalletService(walletInfoSource);
}
@override
TransactionPriority getDecredTransactionPriorityMedium() =>
DecredTransactionPriority.medium;
@override
TransactionPriority getDecredTransactionPrioritySlow() =>
DecredTransactionPriority.slow;
}

View file

@ -62,6 +62,7 @@ import 'package:cake_wallet/haven/haven.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/decred/decred.dart';
import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/solana/solana.dart';
@ -1093,6 +1094,8 @@ Future<void> setup({
return tron!.createTronWalletService(_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
case WalletType.wownero:
return wownero!.createWowneroWalletService(_walletInfoSource, _unspentCoinsInfoSource);
case WalletType.decred:
return decred!.createDecredWalletService(_walletInfoSource);
case WalletType.none:
throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService');
}

View file

@ -9,6 +9,7 @@ class PreferencesKey {
static const currentPolygonNodeIdKey = 'current_node_id_matic';
static const currentNanoNodeIdKey = 'current_node_id_nano';
static const currentNanoPowNodeIdKey = 'current_node_id_nano_pow';
static const currentDecredNodeIdKey = 'current_node_id_decred';
static const currentBananoNodeIdKey = 'current_node_id_banano';
static const currentBananoPowNodeIdKey = 'current_node_id_banano_pow';
static const currentFiatCurrencyKey = 'current_fiat_currency';

View file

@ -76,6 +76,7 @@ class ProvidersHelper {
];
case WalletType.none:
case WalletType.haven:
case WalletType.decred:
return [];
}
}
@ -109,6 +110,7 @@ class ProvidersHelper {
case WalletType.none:
case WalletType.haven:
case WalletType.wownero:
case WalletType.decred:
return [];
}
}

View file

@ -46,6 +46,7 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
final solanaIcon = Image.asset('assets/images/sol_icon.png', height: 24, width: 24);
final tronIcon = Image.asset('assets/images/trx_icon.png', height: 24, width: 24);
final wowneroIcon = Image.asset('assets/images/wownero_icon.png', height: 24, width: 24);
final decredIcon = Image.asset('assets/images/decred_icon.png', height: 24, width: 24);
final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
Image _newWalletImage(BuildContext context) => Image.asset(
@ -178,6 +179,8 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
return tronIcon;
case WalletType.wownero:
return wowneroIcon;
case WalletType.decred:
return decredIcon;
default:
return nonWalletTypeIcon;
}

View file

@ -37,7 +37,8 @@ class MenuWidgetState extends State<MenuWidget> {
this.polygonIcon = Image.asset('assets/images/matic_icon.png'),
this.solanaIcon = Image.asset('assets/images/sol_icon.png'),
this.tronIcon = Image.asset('assets/images/trx_icon.png'),
this.wowneroIcon = Image.asset('assets/images/wownero_icon.png');
this.wowneroIcon = Image.asset('assets/images/wownero_icon.png'),
this.decredIcon = Image.asset('assets/images/decred_menu.png');
final largeScreen = 731;
@ -62,6 +63,7 @@ class MenuWidgetState extends State<MenuWidget> {
Image solanaIcon;
Image tronIcon;
Image wowneroIcon;
Image decredIcon;
@override
void initState() {
@ -245,6 +247,8 @@ class MenuWidgetState extends State<MenuWidget> {
return tronIcon;
case WalletType.wownero:
return wowneroIcon;
case WalletType.decred:
return decredIcon;
default:
throw Exception('No icon for ${type.toString()}');
}

View file

@ -122,6 +122,7 @@ class WalletListBodyState extends State<WalletListBody> {
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
final tBitcoinIcon = Image.asset('assets/images/tbtc.png', height: 24, width: 24);
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
final decredIcon = Image.asset('assets/images/decred_icon.png', height: 24, width: 24);
final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
final ethereumIcon = Image.asset('assets/images/eth_icon.png', height: 24, width: 24);
@ -131,6 +132,7 @@ class WalletListBodyState extends State<WalletListBody> {
final solanaIcon = Image.asset('assets/images/sol_icon.png', height: 24, width: 24);
final tronIcon = Image.asset('assets/images/trx_icon.png', height: 24, width: 24);
final wowneroIcon = Image.asset('assets/images/wownero_icon.png', height: 24, width: 24);
final decredIcon = Image.asset('assets/images/decred_icon.png', height: 24, width: 24);
final scrollController = ScrollController();
final double tileHeight = 60;
Flushbar<void>? _progressBar;

View file

@ -816,6 +816,11 @@ abstract class SettingsStoreBase with Store {
Node getCurrentNode(WalletType walletType) {
final node = nodes[walletType];
// TODO: Implement connecting to a user's preferred node.
if (walletType == WalletType.decred) {
return Node();
}
if (node == null) {
throw Exception('No node found for wallet type: ${walletType.toString()}');
}

View file

@ -54,6 +54,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
case WalletType.wownero:
case WalletType.none:
case WalletType.haven:
case WalletType.decred:
return false;
}
}

View file

@ -739,6 +739,10 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
depositCurrency = CryptoCurrency.wow;
receiveCurrency = CryptoCurrency.xmr;
break;
case WalletType.decred:
depositCurrency = CryptoCurrency.dcr;
receiveCurrency = CryptoCurrency.xmr;
break;
case WalletType.none:
break;
}

View file

@ -85,6 +85,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
case WalletType.litecoin:
case WalletType.bitcoinCash:
case WalletType.bitcoin:
case WalletType.decred:
return false;
}
}

View file

@ -6,6 +6,7 @@ import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
import 'package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart';
import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/decred/decred.dart';
import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
import 'package:cake_wallet/entities/contact_record.dart';
import 'package:cake_wallet/entities/wallet_contact.dart';
@ -569,6 +570,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
.createSolanaTransactionCredentials(outputs, currency: selectedCryptoCurrency);
case WalletType.tron:
return tron!.createTronTransactionCredentials(outputs, currency: selectedCryptoCurrency);
case WalletType.decred:
return decred!.createDecredTransactionCredentials(outputs, priority!);
default:
throw Exception('Unexpected wallet type: ${wallet.type}');
}

View file

@ -181,6 +181,8 @@ abstract class TransactionDetailsViewModelBase with Store {
return 'https://tronscan.org/#/transaction/${txId}';
case WalletType.wownero:
return 'https://explore.wownero.com/tx/${txId}';
case WalletType.decred:
return 'https://dcrdata.decred.org/tx/${txId}';
case WalletType.none:
return '';
}
@ -211,6 +213,8 @@ abstract class TransactionDetailsViewModelBase with Store {
return S.current.view_transaction_on + 'tronscan.org';
case WalletType.wownero:
return S.current.view_transaction_on + 'Wownero.com';
case WalletType.decred:
return S.current.view_transaction_on + 'dcrdata.decred.org';
case WalletType.none:
return '';
}

View file

@ -205,6 +205,22 @@ class WowneroURI extends PaymentURI {
}
}
class DecredURI extends PaymentURI {
DecredURI({required String amount, required String address})
: super(amount: amount, address: address);
@override
String toString() {
var base = 'decred:' + address;
if (amount.isNotEmpty) {
base += '?amount=${amount.replaceAll(',', '.')}';
}
return base;
}
}
abstract class WalletAddressListViewModelBase
extends WalletChangeListenerViewModel with Store {
WalletAddressListViewModelBase({
@ -298,9 +314,57 @@ abstract class WalletAddressListViewModelBase
return TronURI(amount: amount, address: address.address);
case WalletType.wownero:
return WowneroURI(amount: amount, address: address.address);
case WalletType.decred:
return DecredURI(amount: amount, address: address.address);
case WalletType.none:
throw Exception('Unexpected type: ${type.toString()}');
}
if (wallet.type == WalletType.haven) {
return HavenURI(amount: amount, address: address.address);
}
if (wallet.type == WalletType.bitcoin) {
return BitcoinURI(amount: amount, address: address.address);
}
if (wallet.type == WalletType.litecoin) {
return LitecoinURI(amount: amount, address: address.address);
}
if (wallet.type == WalletType.ethereum) {
return EthereumURI(amount: amount, address: address.address);
}
if (wallet.type == WalletType.bitcoinCash) {
return BitcoinCashURI(amount: amount, address: address.address);
}
if (wallet.type == WalletType.nano) {
return NanoURI(amount: amount, address: address.address);
}
if (wallet.type == WalletType.polygon) {
return PolygonURI(amount: amount, address: address.address);
}
if (wallet.type == WalletType.solana) {
return SolanaURI(amount: amount, address: address.address);
}
if (wallet.type == WalletType.tron) {
return TronURI(amount: amount, address: address.address);
}
if (wallet.type == WalletType.wownero) {
return WowneroURI(amount: amount, address: address.address);
}
if (wallet.type == WalletType.decred) {
return DecredURI(amount: amount, address: address.address);
}
throw Exception('Unexpected type: ${type.toString()}');
}
@computed

View file

@ -13,6 +13,7 @@ import 'package:cake_wallet/tron/tron.dart';
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
import 'package:cake_wallet/wownero/wownero.dart';
import 'package:cake_wallet/decred/decred.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart';
@ -156,6 +157,8 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
language: options!.first as String,
isPolyseed: options.last as bool,
);
case WalletType.decred:
return decred!.createDecredNewWalletCredentials(name: name);
case WalletType.none:
throw Exception('Unexpected type: ${type.toString()}');
}

View file

@ -11,6 +11,7 @@ import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/solana/solana.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/tron/tron.dart';
import 'package:cake_wallet/decred/decred.dart';
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
@ -162,6 +163,12 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
password: password,
height: height,
);
case WalletType.decred:
return decred!.createDecredRestoreWalletFromSeedCredentials(
name: name,
mnemonic: seed,
password: password,
);
case WalletType.none:
break;
}

View file

@ -11,6 +11,7 @@ cd cw_bitcoin_cash; flutter pub get; dart run build_runner build --delete-confli
cd cw_solana; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd ..
cd cw_tron; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd ..
cd cw_wownero; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd ..
cd cw_decred; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd ..
cd cw_polygon; flutter pub get; cd ..
cd cw_ethereum; flutter pub get; cd ..
cd cw_mweb && flutter pub get && cd ..

View file

@ -10,7 +10,7 @@ case $APP_ANDROID_TYPE in
CONFIG_ARGS="--monero"
;;
$CAKEWALLET)
CONFIG_ARGS="--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron --wownero"
CONFIG_ARGS="--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron --wownero --decred"
if [ "$CW_WITH_HAVEN" = true ];then
CONFIG_ARGS="$CONFIG_ARGS --haven"
fi
@ -26,4 +26,4 @@ flutter pub get
dart run tool/generate_pubspec.dart
flutter pub get
dart run tool/configure.dart $CONFIG_ARGS
cd scripts/android
cd scripts/android

View file

@ -10,6 +10,7 @@ const polygonOutputPath = 'lib/polygon/polygon.dart';
const solanaOutputPath = 'lib/solana/solana.dart';
const tronOutputPath = 'lib/tron/tron.dart';
const wowneroOutputPath = 'lib/wownero/wownero.dart';
const decredOutputPath = 'lib/decred/decred.dart';
const walletTypesPath = 'lib/wallet_types.g.dart';
const secureStoragePath = 'lib/core/secure_storage.dart';
const pubspecDefaultPath = 'pubspec_default.yaml';
@ -28,6 +29,7 @@ Future<void> main(List<String> args) async {
final hasSolana = args.contains('${prefix}solana');
final hasTron = args.contains('${prefix}tron');
final hasWownero = args.contains('${prefix}wownero');
final hasDecred = args.contains('${prefix}decred');
final excludeFlutterSecureStorage = args.contains('${prefix}excludeFlutterSecureStorage');
await generateBitcoin(hasBitcoin);
@ -41,6 +43,7 @@ Future<void> main(List<String> args) async {
await generateTron(hasTron);
await generateWownero(hasWownero);
// await generateBanano(hasEthereum);
await generateDecred(hasDecred);
await generatePubspec(
hasMonero: hasMonero,
@ -55,6 +58,7 @@ Future<void> main(List<String> args) async {
hasSolana: hasSolana,
hasTron: hasTron,
hasWownero: hasWownero,
hasDecred: hasDecred,
);
await generateWalletTypes(
hasMonero: hasMonero,
@ -68,6 +72,7 @@ Future<void> main(List<String> args) async {
hasSolana: hasSolana,
hasTron: hasTron,
hasWownero: hasWownero,
hasDecred: hasDecred,
);
await injectSecureStorage(!excludeFlutterSecureStorage);
}
@ -1398,6 +1403,74 @@ abstract class Tron {
await outputFile.writeAsString(output);
}
Future<void> generateDecred(bool hasImplementation) async {
final outputFile = File(decredOutputPath);
const decredCommonHeaders = """
import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/output_info.dart';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/unspent_transaction_output.dart';
import 'package:cake_wallet/view_model/send/output.dart';
import 'package:hive/hive.dart';""";
const decredCWHeaders = """
import 'package:cw_decred/mnemonic.dart';
import 'package:cw_decred/transaction_priority.dart';
import 'package:cw_decred/wallet.dart';
import 'package:cw_decred/wallet_service.dart';
import 'package:cw_decred/wallet_creation_credentials.dart';
import 'package:cw_decred/amount_format.dart';
import 'package:cw_decred/transaction_credentials.dart';
""";
const decredCwPart = "part 'cw_decred.dart';";
const decredContent = """
abstract class Decred {
TransactionPriority getMediumTransactionPriority();
WalletCredentials createDecredRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password});
WalletCredentials createDecredNewWalletCredentials({required String name, WalletInfo? walletInfo});
List<String> getWordList();
List<TransactionPriority> getTransactionPriorities();
TransactionPriority deserializeDecredTransactionPriority(int raw);
int getFeeRate(Object wallet, TransactionPriority priority);
Future<void> generateNewAddress(Object wallet);
Object createDecredTransactionCredentials(List<Output> outputs, TransactionPriority priority);
List<String> getAddresses(Object wallet);
String getAddress(Object wallet);
String formatterDecredAmountToString({required int amount});
double formatterDecredAmountToDouble({required int amount});
int formatterStringDoubleToDecredAmount(String amount);
List<Unspent> getUnspents(Object wallet);
void updateUnspents(Object wallet);
WalletService createDecredWalletService(Box<WalletInfo> walletInfoSource);
TransactionPriority getDecredTransactionPriorityMedium();
TransactionPriority getDecredTransactionPrioritySlow();
}
""";
const decredEmptyDefinition = 'Decred? decred;\n';
const decredCWDefinition = 'Decred? decred = CWDecred();\n';
final output = '$decredCommonHeaders\n'
+ (hasImplementation ? '$decredCWHeaders\n' : '\n')
+ (hasImplementation ? '$decredCwPart\n\n' : '\n')
+ (hasImplementation ? decredCWDefinition : decredEmptyDefinition)
+ '\n'
+ decredContent;
if (outputFile.existsSync()) {
await outputFile.delete();
}
await outputFile.writeAsString(output);
}
Future<void> generatePubspec({
required bool hasMonero,
required bool hasBitcoin,
@ -1411,6 +1484,7 @@ Future<void> generatePubspec({
required bool hasSolana,
required bool hasTron,
required bool hasWownero,
required bool hasDecred,
}) async {
const cwCore = """
cw_core:
@ -1475,6 +1549,10 @@ Future<void> generatePubspec({
cw_wownero:
path: ./cw_wownero
""";
const cwDecred = """
cw_decred:
path: ./cw_decred
""";
final inputFile = File(pubspecOutputPath);
final inputText = await inputFile.readAsString();
final inputLines = inputText.split('\n');
@ -1524,6 +1602,10 @@ Future<void> generatePubspec({
output += '\n$cwSharedExternal\n$cwHaven';
}
if (hasDecred) {
output += '\n$cwDecred';
}
if (hasFlutterSecureStorage) {
output += '\n$flutterSecureStorage\n';
}
@ -1560,6 +1642,7 @@ Future<void> generateWalletTypes({
required bool hasSolana,
required bool hasTron,
required bool hasWownero,
required bool hasDecred,
}) async {
final walletTypesFile = File(walletTypesPath);
@ -1619,6 +1702,10 @@ Future<void> generateWalletTypes({
outputContent += '\tWalletType.haven,\n';
}
if (hasDecred) {
outputContent += '\tWalletType.decred,\n';
}
outputContent += '];\n';
await walletTypesFile.writeAsString(outputContent);
}