mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-31 06:55:59 +00:00
decred: Add watching only wallets.
This commit is contained in:
parent
2acb68e64c
commit
fa8881f438
12 changed files with 132 additions and 22 deletions
|
@ -57,6 +57,17 @@ void createWalletSync(Map<String, String> args) {
|
|||
);
|
||||
}
|
||||
|
||||
void createWatchOnlyWallet(String walletName, String datadir, String pubkey) {
|
||||
final cName = walletName.toCString();
|
||||
final cDataDir = datadir.toCString();
|
||||
final cPub = pubkey.toCString();
|
||||
final cNet = "testnet".toCString();
|
||||
executePayloadFn(
|
||||
fn: () => dcrwalletApi.createWatchOnlyWallet(cName, cDataDir, cNet, cPub),
|
||||
ptrsToFree: [cName, cDataDir, cNet, cPub],
|
||||
);
|
||||
}
|
||||
|
||||
/// loadWalletAsync calls the libdcrwallet's loadWallet function asynchronously.
|
||||
Future<void> loadWalletAsync({required String name, required String dataDir}) {
|
||||
final args = <String, String>{
|
||||
|
@ -269,6 +280,15 @@ String? newExternalAddress(String walletName) {
|
|||
return res.payload;
|
||||
}
|
||||
|
||||
String defaultPubkey(String walletName) {
|
||||
final cName = walletName.toCString();
|
||||
final res = executePayloadFn(
|
||||
fn: () => dcrwalletApi.defaultPubkey(cName),
|
||||
ptrsToFree: [cName],
|
||||
);
|
||||
return res.payload;
|
||||
}
|
||||
|
||||
String addresses(String walletName) {
|
||||
final cName = walletName.toCString();
|
||||
final res = executePayloadFn(
|
||||
|
|
|
@ -13,6 +13,7 @@ import 'package:cw_decred/api/libdcrwallet.dart' as libdcrwallet;
|
|||
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/wallet_service.dart';
|
||||
import 'package:cw_decred/balance.dart';
|
||||
import 'package:cw_decred/transaction_info.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
@ -37,6 +38,8 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance,
|
|||
: _password = password,
|
||||
this.syncStatus = NotConnectedSyncStatus(),
|
||||
this.unspentCoinsInfo = unspentCoinsInfo,
|
||||
this.watchingOnly =
|
||||
walletInfo.derivationPath == DecredWalletService.pubkeyRestorePath,
|
||||
this.balance =
|
||||
ObservableMap.of({CryptoCurrency.dcr: DecredBalance.zero()}),
|
||||
super(walletInfo) {
|
||||
|
@ -50,6 +53,7 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance,
|
|||
static final defaultFeeRate = 10000;
|
||||
final String _password;
|
||||
final idPrefix = "decred_";
|
||||
bool watchingOnly;
|
||||
bool connecting = false;
|
||||
int bestHeight = 0;
|
||||
String bestHash = "";
|
||||
|
@ -73,12 +77,17 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance,
|
|||
|
||||
@override
|
||||
String? get seed {
|
||||
if (watchingOnly) {
|
||||
return null;
|
||||
}
|
||||
return libdcrwallet.walletSeed(walletInfo.name, _password);
|
||||
}
|
||||
|
||||
@override
|
||||
Object get keys {
|
||||
return {};
|
||||
Object get keys => {};
|
||||
|
||||
String get pubkey {
|
||||
return libdcrwallet.defaultPubkey(walletInfo.name);
|
||||
}
|
||||
|
||||
Future<void> init() async {
|
||||
|
@ -240,6 +249,16 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance,
|
|||
|
||||
@override
|
||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||
if (watchingOnly) {
|
||||
return DecredPendingTransaction(
|
||||
txid: "",
|
||||
amount: 0,
|
||||
fee: 0,
|
||||
rawHex: "",
|
||||
send: () async {
|
||||
throw "unable to send with watching only wallet";
|
||||
});
|
||||
}
|
||||
final inputs = [];
|
||||
this.unspentCoinsInfo.values.forEach((unspent) {
|
||||
if (unspent.isSending) {
|
||||
|
@ -417,6 +436,9 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance,
|
|||
|
||||
@override
|
||||
Future<void> changePassword(String password) async {
|
||||
if (watchingOnly) {
|
||||
return;
|
||||
}
|
||||
return () async {
|
||||
libdcrwallet.changeWalletPassword(walletInfo.name, _password, password);
|
||||
}();
|
||||
|
|
|
@ -18,17 +18,15 @@ class DecredRestoreWalletFromSeedCredentials extends WalletCredentials {
|
|||
final String mnemonic;
|
||||
}
|
||||
|
||||
class DecredRestoreWalletFromWIFCredentials extends WalletCredentials {
|
||||
DecredRestoreWalletFromWIFCredentials(
|
||||
class DecredRestoreWalletFromPubkeyCredentials extends WalletCredentials {
|
||||
DecredRestoreWalletFromPubkeyCredentials(
|
||||
{required String name,
|
||||
required String password,
|
||||
required this.wif,
|
||||
required String this.pubkey,
|
||||
WalletInfo? walletInfo})
|
||||
: t = throw UnimplementedError(), // TODO: Maybe can be used to create watching only wallets?
|
||||
super(name: name, password: password, walletInfo: walletInfo);
|
||||
: super(name: name, password: password, walletInfo: walletInfo);
|
||||
|
||||
final String wif;
|
||||
final void t;
|
||||
final String pubkey;
|
||||
}
|
||||
|
||||
class DecredRestoreWalletFromHardwareCredentials extends WalletCredentials {
|
||||
|
|
|
@ -20,6 +20,8 @@ class DecredWalletService extends WalletService<
|
|||
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
||||
final seedRestorePath = "m/44'/42'";
|
||||
static final pubkeyRestorePath = "m/44'/42'/0'";
|
||||
|
||||
static void init() async {
|
||||
// Use the general path for all dcr wallets as the general log directory.
|
||||
|
@ -43,6 +45,7 @@ class DecredWalletService extends WalletService<
|
|||
dataDir: credentials.walletInfo!.dirPath,
|
||||
password: credentials.password!,
|
||||
);
|
||||
credentials.walletInfo!.derivationPath = seedRestorePath;
|
||||
final wallet = DecredWallet(credentials.walletInfo!, credentials.password!,
|
||||
this.unspentCoinsInfoSource);
|
||||
await wallet.init();
|
||||
|
@ -101,12 +104,15 @@ class DecredWalletService extends WalletService<
|
|||
password: credentials.password!,
|
||||
mnemonic: credentials.mnemonic,
|
||||
);
|
||||
credentials.walletInfo!.derivationPath = seedRestorePath;
|
||||
final wallet = DecredWallet(credentials.walletInfo!, credentials.password!,
|
||||
this.unspentCoinsInfoSource);
|
||||
await wallet.init();
|
||||
return wallet;
|
||||
}
|
||||
|
||||
// restoreFromKeys only supports restoring a watch only wallet from an account
|
||||
// pubkey.
|
||||
@override
|
||||
Future<DecredWallet> restoreFromKeys(
|
||||
DecredRestoreWalletFromPubkeyCredentials credentials,
|
||||
|
|
|
@ -19,6 +19,15 @@ class CWDecred extends Decred {
|
|||
DecredRestoreWalletFromSeedCredentials(
|
||||
name: name, mnemonic: mnemonic, password: password);
|
||||
|
||||
@override
|
||||
WalletCredentials createDecredRestoreWalletFromPubkeyCredentials(
|
||||
{required String name,
|
||||
required String pubkey,
|
||||
required String password}) =>
|
||||
DecredRestoreWalletFromPubkeyCredentials(
|
||||
name: name, pubkey: pubkey, password: password);
|
||||
|
||||
@override
|
||||
WalletService createDecredWalletService(Box<WalletInfo> walletInfoSource,
|
||||
Box<UnspentCoinsInfo> unspentCoinSource) {
|
||||
return DecredWalletService(walletInfoSource, unspentCoinSource);
|
||||
|
@ -117,6 +126,12 @@ class CWDecred extends Decred {
|
|||
return (minutesDiff / 5).toInt();
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> getDecredWordList() => wordlist;
|
||||
@override
|
||||
List<String> getDecredWordList() => wordlist;
|
||||
|
||||
@override
|
||||
String pubkey(Object wallet) {
|
||||
final decredWallet = wallet as DecredWallet;
|
||||
return decredWallet.pubkey;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ class WalletRestoreFromKeysFrom extends StatefulWidget {
|
|||
WalletRestoreFromKeysFrom({
|
||||
required this.walletRestoreViewModel,
|
||||
required this.onPrivateKeyChange,
|
||||
required this.onViewKeyEntered,
|
||||
required this.displayPrivateKeyField,
|
||||
required this.onHeightOrDateEntered,
|
||||
required this.displayWalletPassword,
|
||||
|
@ -25,6 +26,7 @@ class WalletRestoreFromKeysFrom extends StatefulWidget {
|
|||
final Function(bool) onHeightOrDateEntered;
|
||||
final WalletRestoreViewModel walletRestoreViewModel;
|
||||
final void Function(String)? onPrivateKeyChange;
|
||||
final void Function(bool)? onViewKeyEntered;
|
||||
final bool displayPrivateKeyField;
|
||||
final bool displayWalletPassword;
|
||||
final void Function(String)? onPasswordChange;
|
||||
|
@ -80,6 +82,10 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
|||
}
|
||||
widget.onPrivateKeyChange?.call(privateKeyController.text);
|
||||
});
|
||||
|
||||
viewKeyController.addListener(() {
|
||||
widget.onViewKeyEntered?.call(viewKeyController.text.isNotEmpty);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -168,6 +174,19 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
|||
}
|
||||
|
||||
Widget _restoreFromKeysFormFields() {
|
||||
// Decred can only restore a view only wallet with an account pubkey. Other
|
||||
// fields are not used.
|
||||
if (widget.walletRestoreViewModel.type == WalletType.decred) {
|
||||
return Column(
|
||||
children: [
|
||||
BaseTextFormField(
|
||||
controller: viewKeyController,
|
||||
hintText: S.of(context).view_key_public,
|
||||
maxLines: null,
|
||||
)],
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.displayPrivateKeyField) {
|
||||
// the term "private key" isn't actually what we're accepting here, and it's confusing to
|
||||
// users of the nano community, what this form actually accepts (when importing for nano) is a nano seed in it's hex form, referred to in code as a "seed key"
|
||||
|
|
|
@ -67,6 +67,11 @@ class WalletRestorePage extends BasePage {
|
|||
walletRestoreViewModel.isButtonEnabled = _isValidSeedKey();
|
||||
}
|
||||
},
|
||||
onViewKeyEntered: (bool entered) {
|
||||
if (walletRestoreViewModel.type == WalletType.decred) {
|
||||
walletRestoreViewModel.isButtonEnabled = entered;
|
||||
}
|
||||
},
|
||||
displayPrivateKeyField: walletRestoreViewModel.hasRestoreFromPrivateKey,
|
||||
displayWalletPassword: walletRestoreViewModel.hasWalletPassword,
|
||||
onPasswordChange: (String password) => walletRestoreViewModel.walletPassword = password,
|
||||
|
@ -336,14 +341,16 @@ class WalletRestorePage extends BasePage {
|
|||
credentials['name'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.text;
|
||||
} else {
|
||||
credentials['address'] = walletRestoreFromKeysFormKey.currentState!.addressController.text;
|
||||
credentials['viewKey'] = walletRestoreFromKeysFormKey.currentState!.viewKeyController.text;
|
||||
credentials['spendKey'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.spendKeyController.text;
|
||||
credentials['height'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.blockchainHeightKey.currentState!.height;
|
||||
credentials['name'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.text;
|
||||
credentials['viewKey'] = walletRestoreFromKeysFormKey.currentState!.viewKeyController.text;
|
||||
if (walletRestoreViewModel.type != WalletType.decred) {
|
||||
credentials['address'] = walletRestoreFromKeysFormKey.currentState!.addressController.text;
|
||||
credentials['spendKey'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.spendKeyController.text;
|
||||
credentials['height'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.blockchainHeightKey.currentState!.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import 'package:cw_core/wallet_type.dart';
|
|||
import 'package:cw_monero/monero_wallet.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/decred/decred.dart';
|
||||
import 'package:polyseed/polyseed.dart';
|
||||
|
||||
part 'wallet_keys_view_model.g.dart';
|
||||
|
@ -132,6 +133,16 @@ abstract class WalletKeysViewModelBase with Store {
|
|||
}
|
||||
}
|
||||
|
||||
if (_appStore.wallet!.type == WalletType.decred) {
|
||||
final seed = _appStore.wallet!.seed;
|
||||
final pubkey = decred!.pubkey(_appStore.wallet!);
|
||||
items.addAll([
|
||||
if (seed != null)
|
||||
StandartListItem(title: S.current.wallet_seed, value: seed),
|
||||
StandartListItem(title: S.current.view_key_public, value: pubkey),
|
||||
]);
|
||||
}
|
||||
|
||||
if (_appStore.wallet!.type == WalletType.haven) {
|
||||
final keys = haven!.getKeys(_appStore.wallet!);
|
||||
|
||||
|
@ -227,7 +238,6 @@ abstract class WalletKeysViewModelBase with Store {
|
|||
|
||||
if (_appStore.wallet!.type == WalletType.bitcoin ||
|
||||
_appStore.wallet!.type == WalletType.litecoin ||
|
||||
_appStore.wallet!.type == WalletType.decred ||
|
||||
_appStore.wallet!.type == WalletType.bitcoinCash) {
|
||||
// final keys = bitcoin!.getWalletKeys(_appStore.wallet!);
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
case WalletType.haven:
|
||||
case WalletType.ethereum:
|
||||
case WalletType.polygon:
|
||||
case WalletType.decred:
|
||||
availableModes = [WalletRestoreMode.seed, WalletRestoreMode.keys];
|
||||
break;
|
||||
case WalletType.bitcoin:
|
||||
|
@ -245,6 +246,12 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
password: password,
|
||||
language: 'English',
|
||||
);
|
||||
case WalletType.decred:
|
||||
return decred!.createDecredRestoreWalletFromPubkeyCredentials(
|
||||
name: name,
|
||||
password: password,
|
||||
pubkey: viewKey!,
|
||||
);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
CW_DECRED_DIR=${WORKDIR}/cake_wallet/cw_decred
|
||||
LIBWALLET_PATH="${WORKDIR}/decred/libwallet"
|
||||
LIBWALLET_URL="https://github.com/decred/libwallet.git"
|
||||
LIBWALLET_COMMIT="9f39f38b460e2dece5704cbc4aee293c741ee710"
|
||||
LIBWALLET_VERSION="v1.0.0"
|
||||
|
||||
if [ -e $LIBWALLET_PATH ]; then
|
||||
rm -fr $LIBWALLET_PATH
|
||||
|
@ -12,7 +12,7 @@ fi
|
|||
mkdir -p $LIBWALLET_PATH
|
||||
git clone $LIBWALLET_URL $LIBWALLET_PATH
|
||||
cd $LIBWALLET_PATH
|
||||
git checkout $LIBWALLET_COMMIT
|
||||
git checkout $LIBWALLET_VERSION
|
||||
|
||||
export CPATH="$(clang -v 2>&1 | grep "Selected GCC installation" | rev | cut -d' ' -f1 | rev)/include"
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
. ./config.sh
|
||||
LIBWALLET_PATH="${EXTERNAL_IOS_SOURCE_DIR}/libwallet"
|
||||
LIBWALLET_URL="https://github.com/decred/libwallet.git"
|
||||
LIBWALLET_COMMIT="9f39f38b460e2dece5704cbc4aee293c741ee710"
|
||||
LIBWALLET_VERSION="v1.0.0"
|
||||
|
||||
if [ -e $LIBWALLET_PATH ]; then
|
||||
rm -fr $LIBWALLET_PATH
|
||||
|
@ -11,7 +11,7 @@ fi
|
|||
mkdir -p $LIBWALLET_PATH
|
||||
git clone $LIBWALLET_URL $LIBWALLET_PATH
|
||||
cd $LIBWALLET_PATH
|
||||
git checkout $LIBWALLET_COMMIT
|
||||
git checkout $LIBWALLET_VERSION
|
||||
|
||||
SYSROOT=`xcrun --sdk iphoneos --show-sdk-path`
|
||||
CLANG="clang -isysroot ${SYSROOT}"
|
||||
|
|
|
@ -1439,6 +1439,10 @@ abstract class Decred {
|
|||
{required String name,
|
||||
required String mnemonic,
|
||||
required String password});
|
||||
WalletCredentials createDecredRestoreWalletFromPubkeyCredentials(
|
||||
{required String name,
|
||||
required String pubkey,
|
||||
required String password});
|
||||
WalletService createDecredWalletService(Box<WalletInfo> walletInfoSource,
|
||||
Box<UnspentCoinsInfo> unspentCoinSource);
|
||||
|
||||
|
@ -1466,6 +1470,8 @@ abstract class Decred {
|
|||
int heightByDate(DateTime date);
|
||||
|
||||
List<String> getDecredWordList();
|
||||
|
||||
String pubkey(Object wallet);
|
||||
}
|
||||
""";
|
||||
|
||||
|
|
Loading…
Reference in a new issue