mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 11:39:22 +00:00
Bitcoin derivations (#1089)
* - Update and Fix Conflicts with main * Add Balances for ERC20 tokens * Fix conflicts with main * Add erc20 abi json * Add send erc20 tokens initial function * add missing getHeightByDate in Haven [skip ci] * Allow contacts and wallets from the same tag * Add Shiba Inu icon * Add send ERC-20 tokens initial flow * Add missing import in generated file * Add initial approach for transaction sending for ERC-20 tokens * Refactor signing/sending transactions * Add initial flow for transactions subscription * Refactor signing/sending transactions * Add home settings icon * Fix conflicts with main * Initial flow for home settings * Add logic flow for adding erc20 tokens * Fix initial UI * Finalize UI for Tokens * Integrate UI with Ethereum flow * Add "Enable/Disable" feature for ERC20 tokens * Add initial Erc20 tokens * Add Sorting and Pin Native Token features * Fix price sorting * Sort tokens list as well when Sort criteria changes * - Improve sorting balances flow - Add initial add token from search bar flow * Fix Accounts Popup UI * Fix Pin native token * Fix Enabling/Disabling tokens Fix sorting by fiat once app is opened Improve token availability mechanism * Fix deleting token Fix renaming tokens * Fix issue with search * Add more tokens * - Fix scroll issue - Add ERC20 tokens placeholder image in picker * - Separate and organize default erc20 tokens - Fix scrolling - Add token placeholder images in picker - Sort disabled tokens alphabetically * Change BNB token initial availability [skip ci] * Fix Conflicts with main * Fix Conflicts with main * Add Verse ERC20 token to the initial tokens list * Add rename wallet to Ethereum * Integrate EtherScan API for fetching address transactions Generate Ethereum specific secrets in Ethereum package * Adjust transactions fiat price for ERC20 tokens * Free Up GitHub Actions Ubuntu Runner Disk Space * Free Up GitHub Actions Ubuntu Runner Disk space (trial 2) * Fix Transaction Fee display * Save transaction history * Enhance loading time for erc20 tokens transactions * Minor Fixes and Enhancements * Fix sending erc20 fix block explorer issue * Fix int overflow * Fix transaction amount conversions * Minor: `slow` -> `Slow` [skip-ci] * initial changes * more base config stuff * config changes * successfully builds! * save * successfully add nano wallet * save * seed generation * receive screen + node screen working * tx history working and fiat fixes * balance working * derivation updates * nano-unfinished * sends working * remove fees from send screen, send and receive transactions working * fixes + auto receive incoming txs * fix for scanning QR codes * save * update translations * fixes * more fixes * more strings * small fix * fix github actions workflow * potential fix * potential fix * ci/cd fix * change rep working * seed generation fixes * fixes * save * change rep screen functional * save * banano changes * fixes, start adding ui for PoW * pow node changes * update translations * fix * account changing barely working * save * disable account generation * small fix * save * UI work * save * fixes after merge main * fixes * remove monero stuff, work on derivation ui * lots of fixes + finish up seed derivation * last minute fixes * node related fixes * more fixes * small fix * more fixes * fixes * pretty big refactor for pow, still some bugs * finally works! * get transactions after send * fix * merge conflict fixes * save * fix pow node showing up twice * done * initial changes * small fix * more merge fixes * fixes * more fixes * fix * save * fix manage pow nodes setting appearing on other wallets * fix contact bug * fixes * fiat fixes * save * save * save * save * updates * cleanup * restore fix * fixes * remove deprecated alert * fix * small fix * remove outdated warning * electrum restore fixes * fixes * fixes * fix * derivation fixes * nano fixes pt.1 * nano fixes pt.2 * bip39 fixes * pownode refactor * nodes pages fixes * observer fix * ssl fix * remove old references * remove unused imports * code cleanup * small fix * small potential fix * save * derivation fixes * deterministic fix * fix pt.2 * derivation class fixes * review fixes from nano that also apply here * formatting * stuff that should've stayed deleted * post merge fixes * remove problematic imports and duplicate changes * Delete lib/nano/nano.dart * move wallet restore page proxy code to the view model * fix dashboard page indicators being the same color * debatably better refactoring of derivationInfo, migration needed * additional refactor improvements * blanket comment some stuff out to narrow down this issue * refactor fixes * fix nano exchange * fix , bug, i.e. replace , with . when making a nano transaction * fix nano sending, update restore page wording, and other minor fixes * write migration for existing bitcoin and nano wallets * merge fixes * minor fixes * use default derivation type when restoring from qr code * fixes for restoring * fixes * fixes * merge fix * Fix issues with Creating Electrum and Restoring Bip39 * updates & fixes * Add missing case for no transactions BIP39 wallet restore * Make the default BIP39 the 84 derivation path * Add Samourai Deposit * litecoin mnemonic error fix * Bip39 passphrase support (#1412) * save * passphrase working * fix for when loading wallets + translation update * minor fix * Fix Nano * minor fix [skip ci] --------- Co-authored-by: OmarHatem <omarh.ismail1@gmail.com> * change error state seed conditions into throwables [skip ci] * litecoin fixes * Bip39 minor enhancements (#1416) * minor enhancements * rename bitcoin_derivations -> electrum_derivations * Remove duplicate derivations handle default case * minor fix * Enable passphrase for Litecoin * obscure text of passphrase --------- Co-authored-by: OmarHatem <omarh.ismail1@gmail.com> Co-authored-by: Justin Ehrenhofer <justin.ehrenhofer@gmail.com> Co-authored-by: fossephate <fosse@book.local>
This commit is contained in:
parent
9e4a7f4331
commit
509b92e97f
60 changed files with 908 additions and 341 deletions
|
@ -90,8 +90,7 @@ List<bool> prefixMatches(String source, List<String> prefixes) {
|
||||||
return prefixes.map((prefix) => hx.startsWith(prefix.toLowerCase())).toList();
|
return prefixes.map((prefix) => hx.startsWith(prefix.toLowerCase())).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> generateMnemonic(
|
Future<String> generateElectrumMnemonic({int strength = 264, String prefix = segwit}) async {
|
||||||
{int strength = 264, String prefix = segwit}) async {
|
|
||||||
final wordBitlen = logBase(wordlist.length, 2).ceil();
|
final wordBitlen = logBase(wordlist.length, 2).ceil();
|
||||||
final wordCount = strength / wordBitlen;
|
final wordCount = strength / wordBitlen;
|
||||||
final byteCount = ((wordCount * wordBitlen).ceil() / 8).ceil();
|
final byteCount = ((wordCount * wordBitlen).ceil() / 8).ceil();
|
||||||
|
@ -106,22 +105,29 @@ Future<String> generateMnemonic(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> checkIfMnemonicIsElectrum2(String mnemonic) async {
|
||||||
|
return prefixMatches(mnemonic, [segwit]).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> getMnemonicHash(String mnemonic) async {
|
||||||
|
final hmacSha512 = Hmac(sha512, utf8.encode('Seed version'));
|
||||||
|
final digest = hmacSha512.convert(utf8.encode(normalizeText(mnemonic)));
|
||||||
|
final hx = digest.toString();
|
||||||
|
return hx;
|
||||||
|
}
|
||||||
|
|
||||||
Future<Uint8List> mnemonicToSeedBytes(String mnemonic, {String prefix = segwit}) async {
|
Future<Uint8List> mnemonicToSeedBytes(String mnemonic, {String prefix = segwit}) async {
|
||||||
final pbkdf2 = cryptography.Pbkdf2(
|
final pbkdf2 =
|
||||||
macAlgorithm: cryptography.Hmac.sha512(),
|
cryptography.Pbkdf2(macAlgorithm: cryptography.Hmac.sha512(), iterations: 2048, bits: 512);
|
||||||
iterations: 2048,
|
|
||||||
bits: 512);
|
|
||||||
final text = normalizeText(mnemonic);
|
final text = normalizeText(mnemonic);
|
||||||
// pbkdf2.deriveKey(secretKey: secretKey, nonce: nonce)
|
// pbkdf2.deriveKey(secretKey: secretKey, nonce: nonce)
|
||||||
final key = await pbkdf2.deriveKey(
|
final key = await pbkdf2.deriveKey(
|
||||||
secretKey: cryptography.SecretKey(text.codeUnits),
|
secretKey: cryptography.SecretKey(text.codeUnits), nonce: 'electrum'.codeUnits);
|
||||||
nonce: 'electrum'.codeUnits);
|
|
||||||
final bytes = await key.extractBytes();
|
final bytes = await key.extractBytes();
|
||||||
return Uint8List.fromList(bytes);
|
return Uint8List.fromList(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool matchesAnyPrefix(String mnemonic) =>
|
bool matchesAnyPrefix(String mnemonic) => prefixMatches(mnemonic, [segwit]).any((el) => el);
|
||||||
prefixMatches(mnemonic, [segwit]).any((el) => el);
|
|
||||||
|
|
||||||
bool validateMnemonic(String mnemonic, {String prefix = segwit}) {
|
bool validateMnemonic(String mnemonic, {String prefix = segwit}) {
|
||||||
try {
|
try {
|
||||||
|
@ -208,10 +214,8 @@ String removeCJKSpaces(String source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
String normalizeText(String source) {
|
String normalizeText(String source) {
|
||||||
final res = removeCombiningCharacters(unorm.nfkd(source).toLowerCase())
|
final res =
|
||||||
.trim()
|
removeCombiningCharacters(unorm.nfkd(source).toLowerCase()).trim().split('/\s+/').join(' ');
|
||||||
.split('/\s+/')
|
|
||||||
.join(' ');
|
|
||||||
|
|
||||||
return removeCJKSpaces(res);
|
return removeCJKSpaces(res);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
||||||
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
|
||||||
part 'bitcoin_wallet.g.dart';
|
part 'bitcoin_wallet.g.dart';
|
||||||
|
|
||||||
|
@ -30,8 +31,10 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
ElectrumBalance? initialBalance,
|
ElectrumBalance? initialBalance,
|
||||||
Map<String, int>? initialRegularAddressIndex,
|
Map<String, int>? initialRegularAddressIndex,
|
||||||
Map<String, int>? initialChangeAddressIndex,
|
Map<String, int>? initialChangeAddressIndex,
|
||||||
|
String? passphrase,
|
||||||
}) : super(
|
}) : super(
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
|
passphrase: passphrase,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
|
@ -44,14 +47,19 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
currency: CryptoCurrency.btc) {
|
currency: CryptoCurrency.btc) {
|
||||||
|
// in a standard BIP44 wallet, mainHd derivation path = m/84'/0'/0'/0 (account 0, index unspecified here)
|
||||||
|
// the sideHd derivation path = m/84'/0'/0'/1 (account 1, index unspecified here)
|
||||||
|
String derivationPath = walletInfo.derivationInfo!.derivationPath!;
|
||||||
|
String sideDerivationPath = derivationPath.substring(0, derivationPath.length - 1) + "1";
|
||||||
|
final hd = bitcoin.HDWallet.fromSeed(seedBytes, network: networkType);
|
||||||
walletAddresses = BitcoinWalletAddresses(
|
walletAddresses = BitcoinWalletAddresses(
|
||||||
walletInfo,
|
walletInfo,
|
||||||
electrumClient: electrumClient,
|
electrumClient: electrumClient,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
mainHd: hd,
|
mainHd: hd.derivePath(derivationPath),
|
||||||
sideHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/1"),
|
sideHd: hd.derivePath(sideDerivationPath),
|
||||||
network: networkParam ?? network,
|
network: networkParam ?? network,
|
||||||
);
|
);
|
||||||
autorun((_) {
|
autorun((_) {
|
||||||
|
@ -64,6 +72,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
|
String? passphrase,
|
||||||
String? addressPageType,
|
String? addressPageType,
|
||||||
BasedUtxoNetwork? network,
|
BasedUtxoNetwork? network,
|
||||||
List<BitcoinAddressRecord>? initialAddresses,
|
List<BitcoinAddressRecord>? initialAddresses,
|
||||||
|
@ -71,14 +80,29 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
Map<String, int>? initialRegularAddressIndex,
|
Map<String, int>? initialRegularAddressIndex,
|
||||||
Map<String, int>? initialChangeAddressIndex,
|
Map<String, int>? initialChangeAddressIndex,
|
||||||
}) async {
|
}) async {
|
||||||
|
late Uint8List seedBytes;
|
||||||
|
|
||||||
|
switch (walletInfo.derivationInfo?.derivationType) {
|
||||||
|
case DerivationType.bip39:
|
||||||
|
seedBytes = await bip39.mnemonicToSeed(
|
||||||
|
mnemonic,
|
||||||
|
passphrase: passphrase ?? "",
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case DerivationType.electrum:
|
||||||
|
default:
|
||||||
|
seedBytes = await mnemonicToSeedBytes(mnemonic);
|
||||||
|
break;
|
||||||
|
}
|
||||||
return BitcoinWallet(
|
return BitcoinWallet(
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
|
passphrase: passphrase ?? "",
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: await mnemonicToSeedBytes(mnemonic),
|
seedBytes: seedBytes,
|
||||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
addressPageType: addressPageType,
|
addressPageType: addressPageType,
|
||||||
|
@ -97,14 +121,38 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
: BitcoinNetwork.mainnet;
|
: BitcoinNetwork.mainnet;
|
||||||
final snp = await ElectrumWalletSnapshot.load(name, walletInfo.type, password, network);
|
final snp = await ElectrumWalletSnapshot.load(name, walletInfo.type, password, network);
|
||||||
|
|
||||||
|
walletInfo.derivationInfo ??= DerivationInfo(
|
||||||
|
derivationType: snp.derivationType ?? DerivationType.electrum,
|
||||||
|
derivationPath: snp.derivationPath,
|
||||||
|
);
|
||||||
|
|
||||||
|
// set the default if not present:
|
||||||
|
walletInfo.derivationInfo!.derivationPath = snp.derivationPath ?? "m/0'/1";
|
||||||
|
|
||||||
|
late Uint8List seedBytes;
|
||||||
|
|
||||||
|
switch (walletInfo.derivationInfo!.derivationType) {
|
||||||
|
case DerivationType.electrum:
|
||||||
|
seedBytes = await mnemonicToSeedBytes(snp.mnemonic);
|
||||||
|
break;
|
||||||
|
case DerivationType.bip39:
|
||||||
|
default:
|
||||||
|
seedBytes = await bip39.mnemonicToSeed(
|
||||||
|
snp.mnemonic,
|
||||||
|
passphrase: snp.passphrase ?? '',
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return BitcoinWallet(
|
return BitcoinWallet(
|
||||||
mnemonic: snp.mnemonic,
|
mnemonic: snp.mnemonic,
|
||||||
password: password,
|
password: password,
|
||||||
|
passphrase: snp.passphrase,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
initialAddresses: snp.addresses,
|
initialAddresses: snp.addresses,
|
||||||
initialBalance: snp.balance,
|
initialBalance: snp.balance,
|
||||||
seedBytes: await mnemonicToSeedBytes(snp.mnemonic),
|
seedBytes: seedBytes,
|
||||||
initialRegularAddressIndex: snp.regularAddressIndex,
|
initialRegularAddressIndex: snp.regularAddressIndex,
|
||||||
initialChangeAddressIndex: snp.changeAddressIndex,
|
initialChangeAddressIndex: snp.changeAddressIndex,
|
||||||
addressPageType: snp.addressPageType,
|
addressPageType: snp.addressPageType,
|
||||||
|
|
|
@ -2,14 +2,35 @@ import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
|
||||||
class BitcoinNewWalletCredentials extends WalletCredentials {
|
class BitcoinNewWalletCredentials extends WalletCredentials {
|
||||||
BitcoinNewWalletCredentials({required String name, WalletInfo? walletInfo})
|
BitcoinNewWalletCredentials(
|
||||||
: super(name: name, walletInfo: walletInfo);
|
{required String name,
|
||||||
|
WalletInfo? walletInfo,
|
||||||
|
DerivationType? derivationType,
|
||||||
|
String? derivationPath})
|
||||||
|
: super(
|
||||||
|
name: name,
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials {
|
class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials {
|
||||||
BitcoinRestoreWalletFromSeedCredentials(
|
BitcoinRestoreWalletFromSeedCredentials({
|
||||||
{required String name, required String password, required this.mnemonic, WalletInfo? walletInfo})
|
required String name,
|
||||||
: super(name: name, password: password, walletInfo: walletInfo);
|
required String password,
|
||||||
|
required this.mnemonic,
|
||||||
|
WalletInfo? walletInfo,
|
||||||
|
required DerivationType derivationType,
|
||||||
|
required String derivationPath,
|
||||||
|
String? passphrase,
|
||||||
|
}) : super(
|
||||||
|
name: name,
|
||||||
|
password: password,
|
||||||
|
passphrase: passphrase,
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
derivationInfo: DerivationInfo(
|
||||||
|
derivationType: derivationType,
|
||||||
|
derivationPath: derivationPath,
|
||||||
|
));
|
||||||
|
|
||||||
final String mnemonic;
|
final String mnemonic;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
|
||||||
class BitcoinWalletService extends WalletService<BitcoinNewWalletCredentials,
|
class BitcoinWalletService extends WalletService<BitcoinNewWalletCredentials,
|
||||||
BitcoinRestoreWalletFromSeedCredentials, BitcoinRestoreWalletFromWIFCredentials> {
|
BitcoinRestoreWalletFromSeedCredentials, BitcoinRestoreWalletFromWIFCredentials> {
|
||||||
|
@ -29,8 +30,9 @@ class BitcoinWalletService extends WalletService<BitcoinNewWalletCredentials,
|
||||||
credentials.walletInfo?.network = network.value;
|
credentials.walletInfo?.network = network.value;
|
||||||
|
|
||||||
final wallet = await BitcoinWalletBase.create(
|
final wallet = await BitcoinWalletBase.create(
|
||||||
mnemonic: await generateMnemonic(),
|
mnemonic: await generateElectrumMnemonic(),
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
|
passphrase: credentials.passphrase,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
network: network,
|
network: network,
|
||||||
|
@ -105,7 +107,7 @@ class BitcoinWalletService extends WalletService<BitcoinNewWalletCredentials,
|
||||||
@override
|
@override
|
||||||
Future<BitcoinWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials,
|
Future<BitcoinWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials,
|
||||||
{bool? isTestnet}) async {
|
{bool? isTestnet}) async {
|
||||||
if (!validateMnemonic(credentials.mnemonic)) {
|
if (!validateMnemonic(credentials.mnemonic) && !bip39.validateMnemonic(credentials.mnemonic)) {
|
||||||
throw BitcoinMnemonicIsIncorrectException();
|
throw BitcoinMnemonicIsIncorrectException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +116,7 @@ class BitcoinWalletService extends WalletService<BitcoinNewWalletCredentials,
|
||||||
|
|
||||||
final wallet = await BitcoinWalletBase.create(
|
final wallet = await BitcoinWalletBase.create(
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
|
passphrase: credentials.passphrase,
|
||||||
mnemonic: credentials.mnemonic,
|
mnemonic: credentials.mnemonic,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
|
104
cw_bitcoin/lib/electrum_derivations.dart
Normal file
104
cw_bitcoin/lib/electrum_derivations.dart
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
|
||||||
|
Map<DerivationType, List<DerivationInfo>> electrum_derivations = {
|
||||||
|
DerivationType.electrum: [
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.electrum,
|
||||||
|
derivationPath: "m/0'/0",
|
||||||
|
description: "Electrum",
|
||||||
|
scriptType: "p2wpkh",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
DerivationType.bip39: [
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/44'/0'/0'",
|
||||||
|
description: "Standard BIP44",
|
||||||
|
scriptType: "p2pkh",
|
||||||
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/49'/0'/0'",
|
||||||
|
description: "Standard BIP49 compatibility segwit",
|
||||||
|
scriptType: "p2wpkh-p2sh",
|
||||||
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/84'/0'/0'",
|
||||||
|
description: "Standard BIP84 native segwit",
|
||||||
|
scriptType: "p2wpkh",
|
||||||
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/0'",
|
||||||
|
description: "Non-standard legacy",
|
||||||
|
scriptType: "p2pkh",
|
||||||
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/0'",
|
||||||
|
description: "Non-standard compatibility segwit",
|
||||||
|
scriptType: "p2wpkh-p2sh",
|
||||||
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/0'",
|
||||||
|
description: "Non-standard native segwit",
|
||||||
|
scriptType: "p2wpkh",
|
||||||
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/44'/0'/0'",
|
||||||
|
description: "Samourai Deposit",
|
||||||
|
scriptType: "p2wpkh",
|
||||||
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/49'/0'/0'",
|
||||||
|
description: "Samourai Deposit",
|
||||||
|
scriptType: "p2wpkh",
|
||||||
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/84'/0'/2147483644'",
|
||||||
|
description: "Samourai Bad Bank (toxic change)",
|
||||||
|
scriptType: "p2wpkh",
|
||||||
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/84'/0'/2147483645'",
|
||||||
|
description: "Samourai Whirlpool Pre Mix",
|
||||||
|
scriptType: "p2wpkh",
|
||||||
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/84'/0'/2147483646'",
|
||||||
|
description: "Samourai Whirlpool Post Mix",
|
||||||
|
scriptType: "p2wpkh",
|
||||||
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/44'/0'/2147483647'",
|
||||||
|
description: "Samourai Ricochet legacy",
|
||||||
|
scriptType: "p2pkh",
|
||||||
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/49'/0'/2147483647'",
|
||||||
|
description: "Samourai Ricochet compatibility segwit",
|
||||||
|
scriptType: "p2wpkh-p2sh",
|
||||||
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/84'/0'/2147483647'",
|
||||||
|
description: "Samourai Ricochet native segwit",
|
||||||
|
scriptType: "p2wpkh",
|
||||||
|
),
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/84'/2'/0'",
|
||||||
|
description: "Default Litecoin",
|
||||||
|
scriptType: "p2wpkh",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
};
|
|
@ -55,13 +55,15 @@ abstract class ElectrumWalletBase
|
||||||
required this.networkType,
|
required this.networkType,
|
||||||
required this.mnemonic,
|
required this.mnemonic,
|
||||||
required Uint8List seedBytes,
|
required Uint8List seedBytes,
|
||||||
|
this.passphrase,
|
||||||
List<BitcoinAddressRecord>? initialAddresses,
|
List<BitcoinAddressRecord>? initialAddresses,
|
||||||
ElectrumClient? electrumClient,
|
ElectrumClient? electrumClient,
|
||||||
ElectrumBalance? initialBalance,
|
ElectrumBalance? initialBalance,
|
||||||
CryptoCurrency? currency})
|
CryptoCurrency? currency})
|
||||||
: hd = currency == CryptoCurrency.bch
|
: hd = currency == CryptoCurrency.bch
|
||||||
? bitcoinCashHDWallet(seedBytes)
|
? bitcoinCashHDWallet(seedBytes)
|
||||||
: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/0"),
|
: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType)
|
||||||
|
.derivePath(walletInfo.derivationInfo?.derivationPath ?? "m/0'/0"),
|
||||||
syncStatus = NotConnectedSyncStatus(),
|
syncStatus = NotConnectedSyncStatus(),
|
||||||
_password = password,
|
_password = password,
|
||||||
_feeRates = <int>[],
|
_feeRates = <int>[],
|
||||||
|
@ -92,6 +94,7 @@ abstract class ElectrumWalletBase
|
||||||
|
|
||||||
final bitcoin.HDWallet hd;
|
final bitcoin.HDWallet hd;
|
||||||
final String mnemonic;
|
final String mnemonic;
|
||||||
|
final String? passphrase;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@observable
|
@observable
|
||||||
|
@ -617,6 +620,7 @@ abstract class ElectrumWalletBase
|
||||||
|
|
||||||
String toJSON() => json.encode({
|
String toJSON() => json.encode({
|
||||||
'mnemonic': mnemonic,
|
'mnemonic': mnemonic,
|
||||||
|
'passphrase': passphrase ?? '',
|
||||||
'account_index': walletAddresses.currentReceiveAddressIndexByType,
|
'account_index': walletAddresses.currentReceiveAddressIndexByType,
|
||||||
'change_address_index': walletAddresses.currentChangeAddressIndexByType,
|
'change_address_index': walletAddresses.currentChangeAddressIndexByType,
|
||||||
'addresses': walletAddresses.allAddresses.map((addr) => addr.toJSON()).toList(),
|
'addresses': walletAddresses.allAddresses.map((addr) => addr.toJSON()).toList(),
|
||||||
|
@ -624,6 +628,8 @@ abstract class ElectrumWalletBase
|
||||||
? SegwitAddresType.p2wpkh.toString()
|
? SegwitAddresType.p2wpkh.toString()
|
||||||
: walletInfo.addressPageType.toString(),
|
: walletInfo.addressPageType.toString(),
|
||||||
'balance': balance[currency]?.toJSON(),
|
'balance': balance[currency]?.toJSON(),
|
||||||
|
'derivationTypeIndex': walletInfo.derivationInfo?.derivationType?.index,
|
||||||
|
'derivationPath': walletInfo.derivationInfo?.derivationPath,
|
||||||
});
|
});
|
||||||
|
|
||||||
int feeRate(TransactionPriority priority) {
|
int feeRate(TransactionPriority priority) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/utils/file.dart';
|
import 'package:cw_core/utils/file.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
|
@ -17,6 +18,9 @@ class ElectrumWalletSnapshot {
|
||||||
required this.regularAddressIndex,
|
required this.regularAddressIndex,
|
||||||
required this.changeAddressIndex,
|
required this.changeAddressIndex,
|
||||||
required this.addressPageType,
|
required this.addressPageType,
|
||||||
|
this.passphrase,
|
||||||
|
this.derivationType,
|
||||||
|
this.derivationPath,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String name;
|
final String name;
|
||||||
|
@ -29,6 +33,9 @@ class ElectrumWalletSnapshot {
|
||||||
ElectrumBalance balance;
|
ElectrumBalance balance;
|
||||||
Map<String, int> regularAddressIndex;
|
Map<String, int> regularAddressIndex;
|
||||||
Map<String, int> changeAddressIndex;
|
Map<String, int> changeAddressIndex;
|
||||||
|
String? passphrase;
|
||||||
|
DerivationType? derivationType;
|
||||||
|
String? derivationPath;
|
||||||
|
|
||||||
static Future<ElectrumWalletSnapshot> load(
|
static Future<ElectrumWalletSnapshot> load(
|
||||||
String name, WalletType type, String password, BasedUtxoNetwork network) async {
|
String name, WalletType type, String password, BasedUtxoNetwork network) async {
|
||||||
|
@ -37,6 +44,7 @@ class ElectrumWalletSnapshot {
|
||||||
final data = json.decode(jsonSource) as Map;
|
final data = json.decode(jsonSource) as Map;
|
||||||
final addressesTmp = data['addresses'] as List? ?? <Object>[];
|
final addressesTmp = data['addresses'] as List? ?? <Object>[];
|
||||||
final mnemonic = data['mnemonic'] as String;
|
final mnemonic = data['mnemonic'] as String;
|
||||||
|
final passphrase = data['passphrase'] as String? ?? '';
|
||||||
final addresses = addressesTmp
|
final addresses = addressesTmp
|
||||||
.whereType<String>()
|
.whereType<String>()
|
||||||
.map((addr) => BitcoinAddressRecord.fromJSON(addr, network))
|
.map((addr) => BitcoinAddressRecord.fromJSON(addr, network))
|
||||||
|
@ -46,6 +54,10 @@ class ElectrumWalletSnapshot {
|
||||||
var regularAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0};
|
var regularAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0};
|
||||||
var changeAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0};
|
var changeAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0};
|
||||||
|
|
||||||
|
final derivationType =
|
||||||
|
DerivationType.values[(data['derivationTypeIndex'] as int?) ?? DerivationType.electrum.index];
|
||||||
|
final derivationPath = data['derivationPath'] as String? ?? "m/0'/0";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
regularAddressIndexByType = {
|
regularAddressIndexByType = {
|
||||||
SegwitAddresType.p2wpkh.toString(): int.parse(data['account_index'] as String? ?? '0')
|
SegwitAddresType.p2wpkh.toString(): int.parse(data['account_index'] as String? ?? '0')
|
||||||
|
@ -65,12 +77,15 @@ class ElectrumWalletSnapshot {
|
||||||
name: name,
|
name: name,
|
||||||
type: type,
|
type: type,
|
||||||
password: password,
|
password: password,
|
||||||
|
passphrase: passphrase,
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
addresses: addresses,
|
addresses: addresses,
|
||||||
balance: balance,
|
balance: balance,
|
||||||
regularAddressIndex: regularAddressIndexByType,
|
regularAddressIndex: regularAddressIndexByType,
|
||||||
changeAddressIndex: changeAddressIndexByType,
|
changeAddressIndex: changeAddressIndexByType,
|
||||||
addressPageType: data['address_page_type'] as String?,
|
addressPageType: data['address_page_type'] as String?,
|
||||||
|
derivationType: derivationType,
|
||||||
|
derivationPath: derivationPath,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
import 'package:cw_bitcoin/litecoin_network.dart';
|
import 'package:cw_bitcoin/litecoin_network.dart';
|
||||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||||
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
|
||||||
part 'litecoin_wallet.g.dart';
|
part 'litecoin_wallet.g.dart';
|
||||||
|
|
||||||
|
@ -62,11 +63,26 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
|
String? passphrase,
|
||||||
String? addressPageType,
|
String? addressPageType,
|
||||||
List<BitcoinAddressRecord>? initialAddresses,
|
List<BitcoinAddressRecord>? initialAddresses,
|
||||||
ElectrumBalance? initialBalance,
|
ElectrumBalance? initialBalance,
|
||||||
Map<String, int>? initialRegularAddressIndex,
|
Map<String, int>? initialRegularAddressIndex,
|
||||||
Map<String, int>? initialChangeAddressIndex}) async {
|
Map<String, int>? initialChangeAddressIndex}) async {
|
||||||
|
late Uint8List seedBytes;
|
||||||
|
|
||||||
|
switch (walletInfo.derivationInfo?.derivationType) {
|
||||||
|
case DerivationType.bip39:
|
||||||
|
seedBytes = await bip39.mnemonicToSeed(
|
||||||
|
mnemonic,
|
||||||
|
passphrase: passphrase ?? "",
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case DerivationType.electrum:
|
||||||
|
default:
|
||||||
|
seedBytes = await mnemonicToSeedBytes(mnemonic);
|
||||||
|
break;
|
||||||
|
}
|
||||||
return LitecoinWallet(
|
return LitecoinWallet(
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
password: password,
|
password: password,
|
||||||
|
@ -74,7 +90,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: await mnemonicToSeedBytes(mnemonic),
|
seedBytes: seedBytes,
|
||||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
addressPageType: addressPageType,
|
addressPageType: addressPageType,
|
||||||
|
|
|
@ -11,6 +11,7 @@ import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
|
||||||
class LitecoinWalletService extends WalletService<
|
class LitecoinWalletService extends WalletService<
|
||||||
BitcoinNewWalletCredentials,
|
BitcoinNewWalletCredentials,
|
||||||
|
@ -27,8 +28,9 @@ class LitecoinWalletService extends WalletService<
|
||||||
@override
|
@override
|
||||||
Future<LitecoinWallet> create(BitcoinNewWalletCredentials credentials, {bool? isTestnet}) async {
|
Future<LitecoinWallet> create(BitcoinNewWalletCredentials credentials, {bool? isTestnet}) async {
|
||||||
final wallet = await LitecoinWalletBase.create(
|
final wallet = await LitecoinWalletBase.create(
|
||||||
mnemonic: await generateMnemonic(),
|
mnemonic: await generateElectrumMnemonic(),
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
|
passphrase: credentials.passphrase,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
unspentCoinsInfo: unspentCoinsInfoSource);
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
|
@ -100,12 +102,13 @@ class LitecoinWalletService extends WalletService<
|
||||||
@override
|
@override
|
||||||
Future<LitecoinWallet> restoreFromSeed(
|
Future<LitecoinWallet> restoreFromSeed(
|
||||||
BitcoinRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async {
|
BitcoinRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async {
|
||||||
if (!validateMnemonic(credentials.mnemonic)) {
|
if (!validateMnemonic(credentials.mnemonic) && !bip39.validateMnemonic(credentials.mnemonic)) {
|
||||||
throw LitecoinMnemonicIsIncorrectException();
|
throw LitecoinMnemonicIsIncorrectException();
|
||||||
}
|
}
|
||||||
|
|
||||||
final wallet = await LitecoinWalletBase.create(
|
final wallet = await LitecoinWalletBase.create(
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
|
passphrase: credentials.passphrase,
|
||||||
mnemonic: credentials.mnemonic,
|
mnemonic: credentials.mnemonic,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
unspentCoinsInfo: unspentCoinsInfoSource);
|
||||||
|
|
|
@ -5,29 +5,58 @@ import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||||
import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
|
import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
|
||||||
import 'package:hex/hex.dart';
|
import 'package:hex/hex.dart';
|
||||||
|
|
||||||
bitcoin.PaymentData generatePaymentData({required bitcoin.HDWallet hd, required int index}) =>
|
bitcoin.PaymentData generatePaymentData({required bitcoin.HDWallet hd, int? index}) {
|
||||||
PaymentData(pubkey: Uint8List.fromList(HEX.decode(hd.derive(index).pubKey!)));
|
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
|
||||||
|
return PaymentData(pubkey: Uint8List.fromList(HEX.decode(pubKey)));
|
||||||
|
}
|
||||||
|
|
||||||
ECPrivate generateECPrivate(
|
ECPrivate generateECPrivate(
|
||||||
{required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) =>
|
{required bitcoin.HDWallet hd, required BasedUtxoNetwork network, int? index}) {
|
||||||
ECPrivate.fromWif(hd.derive(index).wif!, netVersion: network.wifNetVer);
|
final wif = index != null ? hd.derive(index).wif! : hd.wif!;
|
||||||
|
return ECPrivate.fromWif(wif, netVersion: network.wifNetVer);
|
||||||
|
}
|
||||||
|
|
||||||
String generateP2WPKHAddress(
|
String generateP2WPKHAddress({
|
||||||
{required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) =>
|
required bitcoin.HDWallet hd,
|
||||||
ECPublic.fromHex(hd.derive(index).pubKey!).toP2wpkhAddress().toAddress(network);
|
required BasedUtxoNetwork network,
|
||||||
|
int? index,
|
||||||
|
}) {
|
||||||
|
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
|
||||||
|
return ECPublic.fromHex(pubKey).toP2wpkhAddress().toAddress(network);
|
||||||
|
}
|
||||||
|
|
||||||
String generateP2SHAddress(
|
String generateP2SHAddress({
|
||||||
{required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) =>
|
required bitcoin.HDWallet hd,
|
||||||
ECPublic.fromHex(hd.derive(index).pubKey!).toP2wpkhInP2sh().toAddress(network);
|
required BasedUtxoNetwork network,
|
||||||
|
int? index,
|
||||||
|
}) {
|
||||||
|
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
|
||||||
|
return ECPublic.fromHex(pubKey).toP2wpkhInP2sh().toAddress(network);
|
||||||
|
}
|
||||||
|
|
||||||
String generateP2WSHAddress(
|
String generateP2WSHAddress({
|
||||||
{required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) =>
|
required bitcoin.HDWallet hd,
|
||||||
ECPublic.fromHex(hd.derive(index).pubKey!).toP2wshAddress().toAddress(network);
|
required BasedUtxoNetwork network,
|
||||||
|
int? index,
|
||||||
|
}) {
|
||||||
|
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
|
||||||
|
return ECPublic.fromHex(pubKey).toP2wshAddress().toAddress(network);
|
||||||
|
}
|
||||||
|
|
||||||
String generateP2PKHAddress(
|
String generateP2PKHAddress({
|
||||||
{required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) =>
|
required bitcoin.HDWallet hd,
|
||||||
ECPublic.fromHex(hd.derive(index).pubKey!).toP2pkhAddress().toAddress(network);
|
required BasedUtxoNetwork network,
|
||||||
|
int? index,
|
||||||
|
}) {
|
||||||
|
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
|
||||||
|
return ECPublic.fromHex(pubKey).toP2pkhAddress().toAddress(network);
|
||||||
|
}
|
||||||
|
|
||||||
String generateP2TRAddress(
|
String generateP2TRAddress({
|
||||||
{required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) =>
|
required bitcoin.HDWallet hd,
|
||||||
ECPublic.fromHex(hd.derive(index).pubKey!).toTaprootAddress().toAddress(network);
|
required BasedUtxoNetwork network,
|
||||||
|
int? index,
|
||||||
|
}) {
|
||||||
|
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
|
||||||
|
return ECPublic.fromHex(pubKey).toTaprootAddress().toAddress(network);
|
||||||
|
}
|
||||||
|
|
|
@ -217,10 +217,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
|
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.2"
|
version: "1.17.1"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -434,18 +434,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.16"
|
version: "0.12.15"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "0.2.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -663,10 +663,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0"
|
version: "1.9.1"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -711,10 +711,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.0"
|
version: "0.5.1"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -748,21 +748,13 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: "direct overridden"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: watcher
|
name: watcher
|
||||||
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: web
|
|
||||||
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.1.4-beta"
|
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -796,5 +788,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.1.0-185.0.dev <4.0.0"
|
dart: ">=3.0.0 <4.0.0"
|
||||||
flutter: ">=3.10.0"
|
flutter: ">=3.10.0"
|
||||||
|
|
|
@ -15,3 +15,4 @@ const NANO_ACCOUNT_TYPE_ID = 13;
|
||||||
const POW_NODE_TYPE_ID = 14;
|
const POW_NODE_TYPE_ID = 14;
|
||||||
const DERIVATION_TYPE_TYPE_ID = 15;
|
const DERIVATION_TYPE_TYPE_ID = 15;
|
||||||
const SPL_TOKEN_TYPE_ID = 16;
|
const SPL_TOKEN_TYPE_ID = 16;
|
||||||
|
const DERIVATION_INFO_TYPE_ID = 17;
|
||||||
|
|
|
@ -7,15 +7,19 @@ abstract class WalletCredentials {
|
||||||
this.seedPhraseLength,
|
this.seedPhraseLength,
|
||||||
this.walletInfo,
|
this.walletInfo,
|
||||||
this.password,
|
this.password,
|
||||||
this.derivationType,
|
this.passphrase,
|
||||||
this.derivationPath,
|
this.derivationInfo,
|
||||||
});
|
}) {
|
||||||
|
if (this.walletInfo != null && derivationInfo != null) {
|
||||||
|
this.walletInfo!.derivationInfo = derivationInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final String name;
|
final String name;
|
||||||
final int? height;
|
final int? height;
|
||||||
int? seedPhraseLength;
|
int? seedPhraseLength;
|
||||||
String? password;
|
String? password;
|
||||||
DerivationType? derivationType;
|
String? passphrase;
|
||||||
String? derivationPath;
|
|
||||||
WalletInfo? walletInfo;
|
WalletInfo? walletInfo;
|
||||||
|
DerivationInfo? derivationInfo;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,28 +17,42 @@ enum DerivationType {
|
||||||
@HiveField(3)
|
@HiveField(3)
|
||||||
bip39,
|
bip39,
|
||||||
@HiveField(4)
|
@HiveField(4)
|
||||||
electrum1,
|
electrum,
|
||||||
@HiveField(5)
|
|
||||||
electrum2,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DerivationInfo {
|
@HiveType(typeId: DerivationInfo.typeId)
|
||||||
|
class DerivationInfo extends HiveObject {
|
||||||
DerivationInfo({
|
DerivationInfo({
|
||||||
required this.derivationType,
|
this.derivationType,
|
||||||
this.derivationPath,
|
this.derivationPath,
|
||||||
this.balance = "",
|
this.balance = "",
|
||||||
this.address = "",
|
this.address = "",
|
||||||
this.height = 0,
|
this.transactionsCount = 0,
|
||||||
this.script_type,
|
this.scriptType,
|
||||||
this.description,
|
this.description,
|
||||||
});
|
});
|
||||||
|
|
||||||
String balance;
|
static const typeId = DERIVATION_INFO_TYPE_ID;
|
||||||
|
|
||||||
|
@HiveField(0, defaultValue: '')
|
||||||
String address;
|
String address;
|
||||||
int height;
|
|
||||||
final DerivationType derivationType;
|
@HiveField(1, defaultValue: '')
|
||||||
final String? derivationPath;
|
String balance;
|
||||||
final String? script_type;
|
|
||||||
|
@HiveField(2)
|
||||||
|
int transactionsCount;
|
||||||
|
|
||||||
|
@HiveField(3)
|
||||||
|
DerivationType? derivationType;
|
||||||
|
|
||||||
|
@HiveField(4)
|
||||||
|
String? derivationPath;
|
||||||
|
|
||||||
|
@HiveField(5)
|
||||||
|
final String? scriptType;
|
||||||
|
|
||||||
|
@HiveField(6)
|
||||||
final String? description;
|
final String? description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,8 +71,7 @@ class WalletInfo extends HiveObject {
|
||||||
this.yatEid,
|
this.yatEid,
|
||||||
this.yatLastUsedAddressRaw,
|
this.yatLastUsedAddressRaw,
|
||||||
this.showIntroCakePayCard,
|
this.showIntroCakePayCard,
|
||||||
this.derivationType,
|
this.derivationInfo)
|
||||||
this.derivationPath)
|
|
||||||
: _yatLastUsedAddressController = StreamController<String>.broadcast();
|
: _yatLastUsedAddressController = StreamController<String>.broadcast();
|
||||||
|
|
||||||
factory WalletInfo.external({
|
factory WalletInfo.external({
|
||||||
|
@ -74,8 +87,7 @@ class WalletInfo extends HiveObject {
|
||||||
bool? showIntroCakePayCard,
|
bool? showIntroCakePayCard,
|
||||||
String yatEid = '',
|
String yatEid = '',
|
||||||
String yatLastUsedAddressRaw = '',
|
String yatLastUsedAddressRaw = '',
|
||||||
DerivationType? derivationType,
|
DerivationInfo? derivationInfo,
|
||||||
String? derivationPath,
|
|
||||||
}) {
|
}) {
|
||||||
return WalletInfo(
|
return WalletInfo(
|
||||||
id,
|
id,
|
||||||
|
@ -90,8 +102,8 @@ class WalletInfo extends HiveObject {
|
||||||
yatEid,
|
yatEid,
|
||||||
yatLastUsedAddressRaw,
|
yatLastUsedAddressRaw,
|
||||||
showIntroCakePayCard,
|
showIntroCakePayCard,
|
||||||
derivationType,
|
derivationInfo,
|
||||||
derivationPath);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const typeId = WALLET_INFO_TYPE_ID;
|
static const typeId = WALLET_INFO_TYPE_ID;
|
||||||
|
@ -143,10 +155,10 @@ class WalletInfo extends HiveObject {
|
||||||
List<String>? usedAddresses;
|
List<String>? usedAddresses;
|
||||||
|
|
||||||
@HiveField(16)
|
@HiveField(16)
|
||||||
DerivationType? derivationType;
|
DerivationType? derivationType; // no longer used
|
||||||
|
|
||||||
@HiveField(17)
|
@HiveField(17)
|
||||||
String? derivationPath;
|
String? derivationPath; // no longer used
|
||||||
|
|
||||||
@HiveField(18)
|
@HiveField(18)
|
||||||
String? addressPageType;
|
String? addressPageType;
|
||||||
|
@ -154,6 +166,9 @@ class WalletInfo extends HiveObject {
|
||||||
@HiveField(19)
|
@HiveField(19)
|
||||||
String? network;
|
String? network;
|
||||||
|
|
||||||
|
@HiveField(20)
|
||||||
|
DerivationInfo? derivationInfo;
|
||||||
|
|
||||||
String get yatLastUsedAddress => yatLastUsedAddressRaw ?? '';
|
String get yatLastUsedAddress => yatLastUsedAddressRaw ?? '';
|
||||||
|
|
||||||
set yatLastUsedAddress(String address) {
|
set yatLastUsedAddress(String address) {
|
||||||
|
|
|
@ -149,10 +149,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
|
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.2"
|
version: "1.17.1"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -343,18 +343,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.16"
|
version: "0.12.15"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "0.2.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -564,10 +564,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0"
|
version: "1.9.1"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -612,10 +612,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.0"
|
version: "0.5.1"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -641,21 +641,13 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: "direct overridden"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: watcher
|
name: watcher
|
||||||
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: web
|
|
||||||
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.1.4-beta"
|
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -689,5 +681,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.1.0-185.0.dev <4.0.0"
|
dart: ">=3.0.0 <4.0.0"
|
||||||
flutter: ">=3.10.0"
|
flutter: ">=3.10.0"
|
||||||
|
|
|
@ -43,7 +43,7 @@ abstract class NanoWalletBase
|
||||||
}) : syncStatus = NotConnectedSyncStatus(),
|
}) : syncStatus = NotConnectedSyncStatus(),
|
||||||
_password = password,
|
_password = password,
|
||||||
_mnemonic = mnemonic,
|
_mnemonic = mnemonic,
|
||||||
_derivationType = walletInfo.derivationType!,
|
_derivationType = walletInfo.derivationInfo!.derivationType!,
|
||||||
_isTransactionUpdating = false,
|
_isTransactionUpdating = false,
|
||||||
_client = NanoClient(),
|
_client = NanoClient(),
|
||||||
walletAddresses = NanoWalletAddresses(walletInfo),
|
walletAddresses = NanoWalletAddresses(walletInfo),
|
||||||
|
@ -389,7 +389,10 @@ abstract class NanoWalletBase
|
||||||
derivationType = DerivationType.bip39;
|
derivationType = DerivationType.bip39;
|
||||||
}
|
}
|
||||||
|
|
||||||
walletInfo.derivationType = derivationType;
|
walletInfo.derivationInfo ??= DerivationInfo(derivationType: derivationType);
|
||||||
|
if (walletInfo.derivationInfo!.derivationType == null) {
|
||||||
|
walletInfo.derivationInfo!.derivationType = derivationType;
|
||||||
|
}
|
||||||
|
|
||||||
return NanoWallet(
|
return NanoWallet(
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
|
|
@ -2,8 +2,15 @@ import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
|
||||||
class NanoNewWalletCredentials extends WalletCredentials {
|
class NanoNewWalletCredentials extends WalletCredentials {
|
||||||
NanoNewWalletCredentials({required String name, String? password})
|
NanoNewWalletCredentials({
|
||||||
: super(name: name, password: password);
|
required String name,
|
||||||
|
String? password,
|
||||||
|
DerivationType? derivationType,
|
||||||
|
}) : super(
|
||||||
|
name: name,
|
||||||
|
password: password,
|
||||||
|
derivationInfo: DerivationInfo(derivationType: derivationType),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class NanoRestoreWalletFromSeedCredentials extends WalletCredentials {
|
class NanoRestoreWalletFromSeedCredentials extends WalletCredentials {
|
||||||
|
@ -11,11 +18,11 @@ class NanoRestoreWalletFromSeedCredentials extends WalletCredentials {
|
||||||
required String name,
|
required String name,
|
||||||
required this.mnemonic,
|
required this.mnemonic,
|
||||||
String? password,
|
String? password,
|
||||||
DerivationType? derivationType,
|
required DerivationType derivationType,
|
||||||
}) : super(
|
}) : super(
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
password: password,
|
||||||
derivationType: derivationType,
|
derivationInfo: DerivationInfo(derivationType: derivationType),
|
||||||
);
|
);
|
||||||
|
|
||||||
final String mnemonic;
|
final String mnemonic;
|
||||||
|
@ -30,12 +37,12 @@ class NanoRestoreWalletFromKeysCredentials extends WalletCredentials {
|
||||||
NanoRestoreWalletFromKeysCredentials({
|
NanoRestoreWalletFromKeysCredentials({
|
||||||
required String name,
|
required String name,
|
||||||
required String password,
|
required String password,
|
||||||
|
required DerivationType derivationType,
|
||||||
required this.seedKey,
|
required this.seedKey,
|
||||||
DerivationType? derivationType,
|
|
||||||
}) : super(
|
}) : super(
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
password: password,
|
||||||
derivationType: derivationType,
|
derivationInfo: DerivationInfo(derivationType: derivationType),
|
||||||
);
|
);
|
||||||
|
|
||||||
final String seedKey;
|
final String seedKey;
|
||||||
|
|
|
@ -28,11 +28,11 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||||
@override
|
@override
|
||||||
Future<WalletBase> create(NanoNewWalletCredentials credentials, {bool? isTestnet}) async {
|
Future<WalletBase> create(NanoNewWalletCredentials credentials, {bool? isTestnet}) async {
|
||||||
// nano standard:
|
// nano standard:
|
||||||
DerivationType derivationType = DerivationType.nano;
|
|
||||||
String seedKey = NanoSeeds.generateSeed();
|
String seedKey = NanoSeeds.generateSeed();
|
||||||
String mnemonic = NanoDerivations.standardSeedToMnemonic(seedKey);
|
String mnemonic = NanoDerivations.standardSeedToMnemonic(seedKey);
|
||||||
|
|
||||||
credentials.walletInfo!.derivationType = derivationType;
|
// ensure default if not present:
|
||||||
|
credentials.walletInfo!.derivationInfo ??= DerivationInfo(derivationType: DerivationType.nano);
|
||||||
|
|
||||||
final wallet = NanoWallet(
|
final wallet = NanoWallet(
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
|
@ -88,9 +88,6 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DerivationType derivationType = credentials.derivationType ?? DerivationType.nano;
|
|
||||||
credentials.walletInfo!.derivationType = derivationType;
|
|
||||||
|
|
||||||
String? mnemonic;
|
String? mnemonic;
|
||||||
|
|
||||||
// we can't derive the mnemonic from the key in all cases, only if it's a "nano" seed
|
// we can't derive the mnemonic from the key in all cases, only if it's a "nano" seed
|
||||||
|
@ -128,9 +125,10 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DerivationType derivationType = credentials.derivationType ?? DerivationType.nano;
|
DerivationType derivationType =
|
||||||
|
credentials.walletInfo?.derivationInfo?.derivationType ?? DerivationType.nano;
|
||||||
|
|
||||||
credentials.walletInfo!.derivationType = derivationType;
|
credentials.walletInfo!.derivationInfo ??= DerivationInfo(derivationType: derivationType);
|
||||||
|
|
||||||
final wallet = await NanoWallet(
|
final wallet = await NanoWallet(
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
|
|
|
@ -1,13 +1,22 @@
|
||||||
part of 'bitcoin.dart';
|
part of 'bitcoin.dart';
|
||||||
|
|
||||||
class CWBitcoin extends Bitcoin {
|
class CWBitcoin extends Bitcoin {
|
||||||
@override
|
WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({
|
||||||
TransactionPriority getMediumTransactionPriority() => BitcoinTransactionPriority.medium;
|
required String name,
|
||||||
|
required String mnemonic,
|
||||||
@override
|
required String password,
|
||||||
WalletCredentials createBitcoinRestoreWalletFromSeedCredentials(
|
required DerivationType derivationType,
|
||||||
{required String name, required String mnemonic, required String password}) =>
|
required String derivationPath,
|
||||||
BitcoinRestoreWalletFromSeedCredentials(name: name, mnemonic: mnemonic, password: password);
|
String? passphrase,
|
||||||
|
}) =>
|
||||||
|
BitcoinRestoreWalletFromSeedCredentials(
|
||||||
|
name: name,
|
||||||
|
mnemonic: mnemonic,
|
||||||
|
password: password,
|
||||||
|
derivationType: derivationType,
|
||||||
|
derivationPath: derivationPath,
|
||||||
|
passphrase: passphrase,
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createBitcoinRestoreWalletFromWIFCredentials(
|
WalletCredentials createBitcoinRestoreWalletFromWIFCredentials(
|
||||||
|
@ -23,6 +32,9 @@ class CWBitcoin extends Bitcoin {
|
||||||
{required String name, WalletInfo? walletInfo}) =>
|
{required String name, WalletInfo? walletInfo}) =>
|
||||||
BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo);
|
BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo);
|
||||||
|
|
||||||
|
@override
|
||||||
|
TransactionPriority getMediumTransactionPriority() => BitcoinTransactionPriority.medium;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> getWordList() => wordlist;
|
List<String> getWordList() => wordlist;
|
||||||
|
|
||||||
|
@ -91,8 +103,7 @@ class CWBitcoin extends Bitcoin {
|
||||||
memo: out.memo))
|
memo: out.memo))
|
||||||
.toList(),
|
.toList(),
|
||||||
priority: priority as BitcoinTransactionPriority,
|
priority: priority as BitcoinTransactionPriority,
|
||||||
feeRate: bitcoinFeeRate
|
feeRate: bitcoinFeeRate);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -248,6 +259,137 @@ class CWBitcoin extends Bitcoin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<DerivationType>> compareDerivationMethods(
|
||||||
|
{required String mnemonic, required Node node}) async {
|
||||||
|
if (await checkIfMnemonicIsElectrum2(mnemonic)) {
|
||||||
|
return [DerivationType.electrum];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [DerivationType.bip39, DerivationType.electrum];
|
||||||
|
}
|
||||||
|
|
||||||
|
int _countOccurrences(String str, String charToCount) {
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < str.length; i++) {
|
||||||
|
if (str[i] == charToCount) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<DerivationInfo>> getDerivationsFromMnemonic({
|
||||||
|
required String mnemonic,
|
||||||
|
required Node node,
|
||||||
|
String? passphrase,
|
||||||
|
}) async {
|
||||||
|
List<DerivationInfo> list = [];
|
||||||
|
|
||||||
|
List<DerivationType> types = await compareDerivationMethods(mnemonic: mnemonic, node: node);
|
||||||
|
if (types.length == 1 && types.first == DerivationType.electrum) {
|
||||||
|
return [
|
||||||
|
DerivationInfo(
|
||||||
|
derivationType: DerivationType.electrum,
|
||||||
|
derivationPath: "m/0'/0",
|
||||||
|
description: "Electrum",
|
||||||
|
scriptType: "p2wpkh",
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
final electrumClient = ElectrumClient();
|
||||||
|
await electrumClient.connectToUri(node.uri);
|
||||||
|
|
||||||
|
late BasedUtxoNetwork network;
|
||||||
|
btc.NetworkType networkType;
|
||||||
|
switch (node.type) {
|
||||||
|
case WalletType.litecoin:
|
||||||
|
network = LitecoinNetwork.mainnet;
|
||||||
|
networkType = litecoinNetwork;
|
||||||
|
break;
|
||||||
|
case WalletType.bitcoin:
|
||||||
|
default:
|
||||||
|
network = BitcoinNetwork.mainnet;
|
||||||
|
networkType = btc.bitcoin;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DerivationType dType in electrum_derivations.keys) {
|
||||||
|
late Uint8List seedBytes;
|
||||||
|
if (dType == DerivationType.electrum) {
|
||||||
|
seedBytes = await mnemonicToSeedBytes(mnemonic);
|
||||||
|
} else if (dType == DerivationType.bip39) {
|
||||||
|
seedBytes = bip39.mnemonicToSeed(mnemonic, passphrase: passphrase ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DerivationInfo dInfo in electrum_derivations[dType]!) {
|
||||||
|
try {
|
||||||
|
DerivationInfo dInfoCopy = DerivationInfo(
|
||||||
|
derivationType: dInfo.derivationType,
|
||||||
|
derivationPath: dInfo.derivationPath,
|
||||||
|
description: dInfo.description,
|
||||||
|
scriptType: dInfo.scriptType,
|
||||||
|
);
|
||||||
|
|
||||||
|
String derivationPath = dInfoCopy.derivationPath!;
|
||||||
|
int derivationDepth = _countOccurrences(derivationPath, "/");
|
||||||
|
|
||||||
|
// the correct derivation depth is dependant on the derivation type:
|
||||||
|
// the derivation paths defined in electrum_derivations are at the ROOT level, i.e.:
|
||||||
|
// electrum's format doesn't specify subaddresses, just subaccounts:
|
||||||
|
|
||||||
|
// for BIP44
|
||||||
|
if (derivationDepth == 3) {
|
||||||
|
// we add "/0/0" so that we generate account 0, index 0 and correctly get balance
|
||||||
|
derivationPath += "/0/0";
|
||||||
|
// we don't support sub-ACCOUNTS in bitcoin like we do monero, and so the path dInfoCopy
|
||||||
|
// expects should be ACCOUNT 0, index unspecified:
|
||||||
|
dInfoCopy.derivationPath = dInfoCopy.derivationPath! + "/0";
|
||||||
|
}
|
||||||
|
|
||||||
|
// var hd = bip32.BIP32.fromSeed(seedBytes).derivePath(derivationPath);
|
||||||
|
final hd = btc.HDWallet.fromSeed(
|
||||||
|
seedBytes,
|
||||||
|
network: networkType,
|
||||||
|
).derivePath(derivationPath);
|
||||||
|
|
||||||
|
String? address;
|
||||||
|
switch (dInfoCopy.scriptType) {
|
||||||
|
case "p2wpkh":
|
||||||
|
address = generateP2WPKHAddress(hd: hd, network: network);
|
||||||
|
break;
|
||||||
|
case "p2pkh":
|
||||||
|
address = generateP2PKHAddress(hd: hd, network: network);
|
||||||
|
break;
|
||||||
|
case "p2wpkh-p2sh":
|
||||||
|
address = generateP2SHAddress(hd: hd, network: network);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final sh = scriptHash(address, network: network);
|
||||||
|
final history = await electrumClient.getHistory(sh);
|
||||||
|
|
||||||
|
final balance = await electrumClient.getBalance(sh);
|
||||||
|
dInfoCopy.balance = balance.entries.first.value.toString();
|
||||||
|
dInfoCopy.address = address;
|
||||||
|
dInfoCopy.transactionsCount = history.length;
|
||||||
|
|
||||||
|
list.add(dInfoCopy);
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort the list such that derivations with the most transactions are first:
|
||||||
|
list.sort((a, b) => b.transactionsCount.compareTo(a.transactionsCount));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool hasTaprootInput(PendingTransaction pendingTransaction) {
|
bool hasTaprootInput(PendingTransaction pendingTransaction) {
|
||||||
return (pendingTransaction as PendingBitcoinTransaction).hasTaprootInputs;
|
return (pendingTransaction as PendingBitcoinTransaction).hasTaprootInputs;
|
||||||
|
|
|
@ -220,6 +220,10 @@ Future<void> defaultSettingsMigration(
|
||||||
await updateNanoNodeList(nodes: nodes);
|
await updateNanoNodeList(nodes: nodes);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 32:
|
||||||
|
await updateBtcNanoWalletInfos(walletInfoSource);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -756,6 +760,20 @@ Future<void> changeDefaultMoneroNode(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> updateBtcNanoWalletInfos(Box<WalletInfo> walletsInfoSource) async {
|
||||||
|
for (WalletInfo walletInfo in walletsInfoSource.values) {
|
||||||
|
if (walletInfo.type == WalletType.nano || walletInfo.type == WalletType.bitcoin) {
|
||||||
|
walletInfo.derivationInfo = DerivationInfo(
|
||||||
|
derivationPath: walletInfo.derivationPath,
|
||||||
|
derivationType: walletInfo.derivationType,
|
||||||
|
address: walletInfo.address,
|
||||||
|
transactionsCount: walletInfo.restoreHeight,
|
||||||
|
);
|
||||||
|
await walletInfo.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> changeDefaultBitcoinNode(
|
Future<void> changeDefaultBitcoinNode(
|
||||||
Box<Node> nodeSource, SharedPreferences sharedPreferences) async {
|
Box<Node> nodeSource, SharedPreferences sharedPreferences) async {
|
||||||
const cakeWalletBitcoinNodeUriPattern = '.cakewallet.com';
|
const cakeWalletBitcoinNodeUriPattern = '.cakewallet.com';
|
||||||
|
|
|
@ -51,10 +51,12 @@ class AddressResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
final match = RegExp(addressPattern).firstMatch(raw);
|
final match = RegExp(addressPattern).firstMatch(raw);
|
||||||
return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_'),
|
return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_|ban_'),
|
||||||
(Match match) {
|
(Match match) {
|
||||||
String group = match.group(0)!;
|
String group = match.group(0)!;
|
||||||
if (group.startsWith('bitcoincash:') || group.startsWith('nano_')) {
|
if (group.startsWith('bitcoincash:') ||
|
||||||
|
group.startsWith('nano_') ||
|
||||||
|
group.startsWith('ban_')) {
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
|
|
|
@ -102,6 +102,10 @@ Future<void> initializeAppConfigs() async {
|
||||||
CakeHive.registerAdapter(DerivationTypeAdapter());
|
CakeHive.registerAdapter(DerivationTypeAdapter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!CakeHive.isAdapterRegistered(DERIVATION_INFO_TYPE_ID)) {
|
||||||
|
CakeHive.registerAdapter(DerivationInfoAdapter());
|
||||||
|
}
|
||||||
|
|
||||||
if (!CakeHive.isAdapterRegistered(WALLET_TYPE_TYPE_ID)) {
|
if (!CakeHive.isAdapterRegistered(WALLET_TYPE_TYPE_ID)) {
|
||||||
CakeHive.registerAdapter(WalletTypeAdapter());
|
CakeHive.registerAdapter(WalletTypeAdapter());
|
||||||
}
|
}
|
||||||
|
@ -163,7 +167,7 @@ Future<void> initializeAppConfigs() async {
|
||||||
transactionDescriptions: transactionDescriptions,
|
transactionDescriptions: transactionDescriptions,
|
||||||
secureStorage: secureStorage,
|
secureStorage: secureStorage,
|
||||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||||
initialMigrationVersion: 31,
|
initialMigrationVersion: 32,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,7 @@ class CWNano extends Nano {
|
||||||
NanoNewWalletCredentials(
|
NanoNewWalletCredentials(
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
password: password,
|
||||||
|
derivationType: DerivationType.nano,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -103,15 +104,10 @@ class CWNano extends Nano {
|
||||||
required String name,
|
required String name,
|
||||||
required String password,
|
required String password,
|
||||||
required String mnemonic,
|
required String mnemonic,
|
||||||
DerivationType? derivationType,
|
required DerivationType derivationType,
|
||||||
}) {
|
}) {
|
||||||
if (derivationType == null) {
|
if (mnemonic.split(" ").length == 12 && derivationType != DerivationType.bip39) {
|
||||||
// figure out the derivation type as best we can, otherwise set it to "unknown"
|
throw Exception("Invalid mnemonic for derivation type!");
|
||||||
if (mnemonic.split(" ").length == 12) {
|
|
||||||
derivationType = DerivationType.bip39;
|
|
||||||
} else {
|
|
||||||
derivationType = DerivationType.unknown;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NanoRestoreWalletFromSeedCredentials(
|
return NanoRestoreWalletFromSeedCredentials(
|
||||||
|
@ -127,15 +123,10 @@ class CWNano extends Nano {
|
||||||
required String name,
|
required String name,
|
||||||
required String password,
|
required String password,
|
||||||
required String seedKey,
|
required String seedKey,
|
||||||
DerivationType? derivationType,
|
required DerivationType derivationType,
|
||||||
}) {
|
}) {
|
||||||
if (derivationType == null) {
|
if (seedKey.length == 128 && derivationType != DerivationType.bip39) {
|
||||||
// figure out the derivation type as best we can, otherwise set it to "unknown"
|
throw Exception("Invalid seed key length for derivation type!");
|
||||||
if (seedKey.length == 64) {
|
|
||||||
derivationType = DerivationType.nano;
|
|
||||||
} else {
|
|
||||||
derivationType = DerivationType.unknown;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NanoRestoreWalletFromKeysCredentials(
|
return NanoRestoreWalletFromKeysCredentials(
|
||||||
|
@ -199,7 +190,6 @@ class CWNano extends Nano {
|
||||||
}
|
}
|
||||||
|
|
||||||
class CWNanoUtil extends NanoUtil {
|
class CWNanoUtil extends NanoUtil {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool isValidBip39Seed(String seed) {
|
bool isValidBip39Seed(String seed) {
|
||||||
return NanoDerivations.isValidBip39Seed(seed);
|
return NanoDerivations.isValidBip39Seed(seed);
|
||||||
|
@ -353,4 +343,54 @@ class CWNanoUtil extends NanoUtil {
|
||||||
return [DerivationType.nano, DerivationType.bip39];
|
return [DerivationType.nano, DerivationType.bip39];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<DerivationInfo>> getDerivationsFromMnemonic({
|
||||||
|
String? mnemonic,
|
||||||
|
String? seedKey,
|
||||||
|
required Node node,
|
||||||
|
}) async {
|
||||||
|
List<DerivationInfo> list = [];
|
||||||
|
|
||||||
|
List<DerivationType> possibleDerivationTypes = await compareDerivationMethods(
|
||||||
|
mnemonic: mnemonic,
|
||||||
|
privateKey: seedKey,
|
||||||
|
node: node,
|
||||||
|
);
|
||||||
|
if (possibleDerivationTypes.length == 1) {
|
||||||
|
return [DerivationInfo(derivationType: possibleDerivationTypes.first)];
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountInfoResponse? bip39Info = await nanoUtil!.getInfoFromSeedOrMnemonic(
|
||||||
|
DerivationType.bip39,
|
||||||
|
mnemonic: mnemonic,
|
||||||
|
seedKey: seedKey,
|
||||||
|
node: node,
|
||||||
|
);
|
||||||
|
AccountInfoResponse? standardInfo = await nanoUtil!.getInfoFromSeedOrMnemonic(
|
||||||
|
DerivationType.nano,
|
||||||
|
mnemonic: mnemonic,
|
||||||
|
seedKey: seedKey,
|
||||||
|
node: node,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (standardInfo?.confirmationHeight != null && standardInfo!.confirmationHeight > 0) {
|
||||||
|
list.add(DerivationInfo(
|
||||||
|
derivationType: DerivationType.nano,
|
||||||
|
balance: nanoUtil!.getRawAsUsableString(standardInfo.balance, nanoUtil!.rawPerNano),
|
||||||
|
address: standardInfo.address!,
|
||||||
|
transactionsCount: standardInfo.confirmationHeight,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bip39Info?.confirmationHeight != null && bip39Info!.confirmationHeight > 0) {
|
||||||
|
list.add(DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
balance: nanoUtil!.getRawAsUsableString(bip39Info.balance, nanoUtil!.rawPerNano),
|
||||||
|
address: bip39Info.address!,
|
||||||
|
transactionsCount: bip39Info.confirmationHeight,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
import 'package:cake_wallet/di.dart';
|
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
|
||||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
import 'package:cake_wallet/themes/theme_base.dart';
|
|
||||||
import 'package:cake_wallet/view_model/wallet_restore_choose_derivation_view_model.dart';
|
import 'package:cake_wallet/view_model/wallet_restore_choose_derivation_view_model.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -13,15 +10,14 @@ class WalletRestoreChooseDerivationPage extends BasePage {
|
||||||
WalletRestoreChooseDerivationPage(this.walletRestoreChooseDerivationViewModel) {}
|
WalletRestoreChooseDerivationPage(this.walletRestoreChooseDerivationViewModel) {}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget middle(BuildContext context) => Observer(
|
Widget middle(BuildContext context) => Text(
|
||||||
builder: (_) => Text(
|
|
||||||
S.current.choose_derivation,
|
S.current.choose_derivation,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18.0,
|
fontSize: 18.0,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontFamily: 'Lato',
|
fontFamily: 'Lato',
|
||||||
color: titleColor(context)),
|
color: titleColor(context)),
|
||||||
));
|
);
|
||||||
|
|
||||||
final WalletRestoreChooseDerivationViewModel walletRestoreChooseDerivationViewModel;
|
final WalletRestoreChooseDerivationViewModel walletRestoreChooseDerivationViewModel;
|
||||||
DerivationType derivationType = DerivationType.unknown;
|
DerivationType derivationType = DerivationType.unknown;
|
||||||
|
@ -105,7 +101,7 @@ class WalletRestoreChooseDerivationPage extends BasePage {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"${S.current.transactions}: ${derivation.height}",
|
"${S.current.transactions}: ${derivation.transactionsCount}",
|
||||||
style: Theme.of(context).primaryTextTheme.labelMedium!.copyWith(
|
style: Theme.of(context).primaryTextTheme.labelMedium!.copyWith(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
|
|
|
@ -20,6 +20,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
|
||||||
{Key? key,
|
{Key? key,
|
||||||
required this.displayLanguageSelector,
|
required this.displayLanguageSelector,
|
||||||
required this.displayBlockHeightSelector,
|
required this.displayBlockHeightSelector,
|
||||||
|
required this.displayPassphrase,
|
||||||
required this.type,
|
required this.type,
|
||||||
required this.seedTypeViewModel,
|
required this.seedTypeViewModel,
|
||||||
this.blockHeightFocusNode,
|
this.blockHeightFocusNode,
|
||||||
|
@ -31,6 +32,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
|
||||||
final WalletType type;
|
final WalletType type;
|
||||||
final bool displayLanguageSelector;
|
final bool displayLanguageSelector;
|
||||||
final bool displayBlockHeightSelector;
|
final bool displayBlockHeightSelector;
|
||||||
|
final bool displayPassphrase;
|
||||||
final SeedTypeViewModel seedTypeViewModel;
|
final SeedTypeViewModel seedTypeViewModel;
|
||||||
final FocusNode? blockHeightFocusNode;
|
final FocusNode? blockHeightFocusNode;
|
||||||
final Function(bool)? onHeightOrDateEntered;
|
final Function(bool)? onHeightOrDateEntered;
|
||||||
|
@ -48,6 +50,7 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
||||||
formKey = GlobalKey<FormState>(),
|
formKey = GlobalKey<FormState>(),
|
||||||
languageController = TextEditingController(),
|
languageController = TextEditingController(),
|
||||||
nameTextEditingController = TextEditingController(),
|
nameTextEditingController = TextEditingController(),
|
||||||
|
passphraseController = TextEditingController(),
|
||||||
seedTypeController = TextEditingController();
|
seedTypeController = TextEditingController();
|
||||||
|
|
||||||
final GlobalKey<SeedWidgetState> seedWidgetStateKey;
|
final GlobalKey<SeedWidgetState> seedWidgetStateKey;
|
||||||
|
@ -55,6 +58,7 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
||||||
final TextEditingController languageController;
|
final TextEditingController languageController;
|
||||||
final TextEditingController nameTextEditingController;
|
final TextEditingController nameTextEditingController;
|
||||||
final TextEditingController seedTypeController;
|
final TextEditingController seedTypeController;
|
||||||
|
final TextEditingController passphraseController;
|
||||||
final GlobalKey<FormState> formKey;
|
final GlobalKey<FormState> formKey;
|
||||||
late ReactionDisposer moneroSeedTypeReaction;
|
late ReactionDisposer moneroSeedTypeReaction;
|
||||||
String language;
|
String language;
|
||||||
|
@ -194,6 +198,14 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
||||||
key: blockchainHeightKey,
|
key: blockchainHeightKey,
|
||||||
onHeightOrDateEntered: widget.onHeightOrDateEntered,
|
onHeightOrDateEntered: widget.onHeightOrDateEntered,
|
||||||
hasDatePicker: widget.type == WalletType.monero),
|
hasDatePicker: widget.type == WalletType.monero),
|
||||||
|
if (widget.displayPassphrase) ...[
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
BaseTextFormField(
|
||||||
|
hintText: S.current.passphrase,
|
||||||
|
controller: passphraseController,
|
||||||
|
obscureText: true,
|
||||||
|
),
|
||||||
|
]
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import 'package:cake_wallet/core/execution_state.dart';
|
import 'package:cake_wallet/core/execution_state.dart';
|
||||||
import 'package:cake_wallet/di.dart';
|
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/nano/nano.dart';
|
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_from_keys_form.dart';
|
import 'package:cake_wallet/src/screens/restore/wallet_restore_from_keys_form.dart';
|
||||||
|
@ -9,7 +7,6 @@ import 'package:cake_wallet/src/screens/restore/wallet_restore_from_seed_form.da
|
||||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
|
||||||
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
|
import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
|
||||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
|
@ -17,7 +14,6 @@ import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
||||||
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
||||||
import 'package:cw_core/nano_account_info_response.dart';
|
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -42,6 +38,7 @@ class WalletRestorePage extends BasePage {
|
||||||
displayBlockHeightSelector:
|
displayBlockHeightSelector:
|
||||||
walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
|
walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
|
||||||
displayLanguageSelector: walletRestoreViewModel.hasSeedLanguageSelector,
|
displayLanguageSelector: walletRestoreViewModel.hasSeedLanguageSelector,
|
||||||
|
displayPassphrase: walletRestoreViewModel.hasPassphrase,
|
||||||
type: walletRestoreViewModel.type,
|
type: walletRestoreViewModel.type,
|
||||||
key: walletRestoreFromSeedFormKey,
|
key: walletRestoreFromSeedFormKey,
|
||||||
blockHeightFocusNode: _blockHeightFocusNode,
|
blockHeightFocusNode: _blockHeightFocusNode,
|
||||||
|
@ -99,8 +96,10 @@ class WalletRestorePage extends BasePage {
|
||||||
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
|
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
|
||||||
final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey;
|
final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey;
|
||||||
final FocusNode _blockHeightFocusNode;
|
final FocusNode _blockHeightFocusNode;
|
||||||
DerivationType derivationType = DerivationType.unknown;
|
|
||||||
String? derivationPath = null;
|
// DerivationType derivationType = DerivationType.unknown;
|
||||||
|
// String? derivationPath = null;
|
||||||
|
DerivationInfo? derivationInfo;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
|
@ -298,6 +297,11 @@ class WalletRestorePage extends BasePage {
|
||||||
-1;
|
-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (walletRestoreViewModel.hasPassphrase) {
|
||||||
|
credentials['passphrase'] =
|
||||||
|
walletRestoreFromSeedFormKey.currentState!.passphraseController.text;
|
||||||
|
}
|
||||||
|
|
||||||
credentials['name'] =
|
credentials['name'] =
|
||||||
walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.text;
|
walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.text;
|
||||||
} else if (walletRestoreViewModel.mode == WalletRestoreMode.keys) {
|
} else if (walletRestoreViewModel.mode == WalletRestoreMode.keys) {
|
||||||
|
@ -318,58 +322,11 @@ class WalletRestorePage extends BasePage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
credentials['derivationType'] = this.derivationType;
|
credentials['derivationInfo'] = this.derivationInfo;
|
||||||
credentials['derivationPath'] = this.derivationPath;
|
|
||||||
credentials['walletType'] = walletRestoreViewModel.type;
|
credentials['walletType'] = walletRestoreViewModel.type;
|
||||||
return credentials;
|
return credentials;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<DerivationInfo>> getDerivationInfo(dynamic credentials) async {
|
|
||||||
var list = <DerivationInfo>[];
|
|
||||||
var walletType = credentials["walletType"] as WalletType;
|
|
||||||
var appStore = getIt.get<AppStore>();
|
|
||||||
var node = appStore.settingsStore.getCurrentNode(walletType);
|
|
||||||
|
|
||||||
switch (walletType) {
|
|
||||||
case WalletType.nano:
|
|
||||||
String? mnemonic = credentials['seed'] as String?;
|
|
||||||
String? seedKey = credentials['private_key'] as String?;
|
|
||||||
AccountInfoResponse? bip39Info = await nanoUtil!.getInfoFromSeedOrMnemonic(
|
|
||||||
DerivationType.bip39,
|
|
||||||
mnemonic: mnemonic,
|
|
||||||
seedKey: seedKey,
|
|
||||||
node: node);
|
|
||||||
AccountInfoResponse? standardInfo = await nanoUtil!.getInfoFromSeedOrMnemonic(
|
|
||||||
DerivationType.nano,
|
|
||||||
mnemonic: mnemonic,
|
|
||||||
seedKey: seedKey,
|
|
||||||
node: node,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (standardInfo?.balance != null) {
|
|
||||||
list.add(DerivationInfo(
|
|
||||||
derivationType: DerivationType.nano,
|
|
||||||
balance: nanoUtil!.getRawAsUsableString(standardInfo!.balance, nanoUtil!.rawPerNano),
|
|
||||||
address: standardInfo.address!,
|
|
||||||
height: standardInfo.confirmationHeight,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bip39Info?.balance != null) {
|
|
||||||
list.add(DerivationInfo(
|
|
||||||
derivationType: DerivationType.bip39,
|
|
||||||
balance: nanoUtil!.getRawAsUsableString(bip39Info!.balance, nanoUtil!.rawPerNano),
|
|
||||||
address: bip39Info.address!,
|
|
||||||
height: bip39Info.confirmationHeight,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _confirmForm(BuildContext context) async {
|
Future<void> _confirmForm(BuildContext context) async {
|
||||||
// Dismissing all visible keyboard to provide context for navigation
|
// Dismissing all visible keyboard to provide context for navigation
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
@ -398,51 +355,46 @@ class WalletRestorePage extends BasePage {
|
||||||
|
|
||||||
walletRestoreViewModel.state = IsExecutingState();
|
walletRestoreViewModel.state = IsExecutingState();
|
||||||
|
|
||||||
List<DerivationType> derivationTypes =
|
DerivationInfo? dInfo;
|
||||||
await walletRestoreViewModel.getDerivationTypes(_credentials());
|
|
||||||
|
|
||||||
if (derivationTypes[0] == DerivationType.unknown || derivationTypes.length > 1) {
|
// get info about the different derivations:
|
||||||
// push screen to choose the derivation type:
|
List<DerivationInfo> derivations =
|
||||||
List<DerivationInfo> derivations = await getDerivationInfo(_credentials());
|
await walletRestoreViewModel.getDerivationInfo(_credentials());
|
||||||
|
|
||||||
int derivationsWithHistory = 0;
|
int derivationsWithHistory = 0;
|
||||||
int derivationWithHistoryIndex = 0;
|
int derivationWithHistoryIndex = 0;
|
||||||
for (int i = 0; i < derivations.length; i++) {
|
for (int i = 0; i < derivations.length; i++) {
|
||||||
if (derivations[i].height > 0) {
|
if (derivations[i].transactionsCount > 0) {
|
||||||
derivationsWithHistory++;
|
derivationsWithHistory++;
|
||||||
derivationWithHistoryIndex = i;
|
derivationWithHistoryIndex = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DerivationInfo? derivationInfo;
|
|
||||||
|
|
||||||
if (derivationsWithHistory > 1) {
|
if (derivationsWithHistory > 1) {
|
||||||
derivationInfo = await Navigator.of(context).pushNamed(Routes.restoreWalletChooseDerivation,
|
dInfo = await Navigator.of(context).pushNamed(
|
||||||
arguments: derivations) as DerivationInfo?;
|
Routes.restoreWalletChooseDerivation,
|
||||||
|
arguments: derivations,
|
||||||
|
) as DerivationInfo?;
|
||||||
} else if (derivationsWithHistory == 1) {
|
} else if (derivationsWithHistory == 1) {
|
||||||
derivationInfo = derivations[derivationWithHistoryIndex];
|
dInfo = derivations[derivationWithHistoryIndex];
|
||||||
} else if (derivationsWithHistory == 0) {
|
|
||||||
// default derivation:
|
|
||||||
derivationInfo = DerivationInfo(
|
|
||||||
derivationType: derivationTypes[0],
|
|
||||||
derivationPath: "m/0'/1",
|
|
||||||
height: 0,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (derivationInfo == null) {
|
// get the default derivation for this wallet type:
|
||||||
walletRestoreViewModel.state = InitialExecutionState();
|
if (dInfo == null) {
|
||||||
return;
|
// we only return 1 derivation if we're pretty sure we know which one to use:
|
||||||
}
|
if (derivations.length == 1) {
|
||||||
this.derivationType = derivationInfo.derivationType;
|
dInfo = derivations.first;
|
||||||
this.derivationPath = derivationInfo.derivationPath;
|
|
||||||
} else {
|
} else {
|
||||||
// electrum derivation:
|
// if we have multiple possible derivations, and none have histories
|
||||||
this.derivationType = derivationTypes[0];
|
// we just default to the most common one:
|
||||||
this.derivationPath = "m/0'/1";
|
dInfo = walletRestoreViewModel.getCommonRestoreDerivation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
walletRestoreViewModel.state = InitialExecutionState();
|
this.derivationInfo = dInfo;
|
||||||
|
if (this.derivationInfo == null) {
|
||||||
|
this.derivationInfo = walletRestoreViewModel.getDefaultDerivation();
|
||||||
|
}
|
||||||
|
|
||||||
walletRestoreViewModel.create(options: _credentials());
|
walletRestoreViewModel.create(options: _credentials());
|
||||||
}
|
}
|
||||||
|
|
|
@ -343,8 +343,10 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (this.mounted) {
|
||||||
changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
|
changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
conditionToDetermineIfToUse2FA:
|
conditionToDetermineIfToUse2FA:
|
||||||
widget.walletListViewModel.shouldRequireTOTP2FAForAccessingWallet,
|
widget.walletListViewModel.shouldRequireTOTP2FAForAccessingWallet,
|
||||||
|
|
|
@ -22,6 +22,7 @@ class BaseTextFormField extends StatelessWidget {
|
||||||
this.enabled = true,
|
this.enabled = true,
|
||||||
this.readOnly = false,
|
this.readOnly = false,
|
||||||
this.enableInteractiveSelection = true,
|
this.enableInteractiveSelection = true,
|
||||||
|
this.obscureText = false,
|
||||||
this.validator,
|
this.validator,
|
||||||
this.textStyle,
|
this.textStyle,
|
||||||
this.placeholderTextStyle,
|
this.placeholderTextStyle,
|
||||||
|
@ -57,6 +58,7 @@ class BaseTextFormField extends StatelessWidget {
|
||||||
final String? initialValue;
|
final String? initialValue;
|
||||||
final double borderWidth;
|
final double borderWidth;
|
||||||
final void Function(String)? onSubmit;
|
final void Function(String)? onSubmit;
|
||||||
|
final bool obscureText;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -70,6 +72,7 @@ class BaseTextFormField extends StatelessWidget {
|
||||||
textInputAction: textInputAction,
|
textInputAction: textInputAction,
|
||||||
textAlign: textAlign,
|
textAlign: textAlign,
|
||||||
autovalidateMode: autovalidateMode,
|
autovalidateMode: autovalidateMode,
|
||||||
|
obscureText: obscureText,
|
||||||
maxLines: maxLines,
|
maxLines: maxLines,
|
||||||
inputFormatters: inputFormatters,
|
inputFormatters: inputFormatters,
|
||||||
enabled: enabled,
|
enabled: enabled,
|
||||||
|
|
|
@ -30,8 +30,7 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
|
||||||
spendKey = '',
|
spendKey = '',
|
||||||
wif = '',
|
wif = '',
|
||||||
address = '',
|
address = '',
|
||||||
super(appStore, walletInfoSource, walletCreationService,
|
super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true);
|
||||||
type: type, isRecovery: true);
|
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
int height;
|
int height;
|
||||||
|
@ -51,8 +50,16 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
|
||||||
bool get hasRestorationHeight => type == WalletType.monero;
|
bool get hasRestorationHeight => type == WalletType.monero;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials getCredentialsFromRestoredWallet(dynamic options, RestoredWallet restoreWallet) {
|
WalletCredentials getCredentialsFromRestoredWallet(
|
||||||
|
dynamic options, RestoredWallet restoreWallet) {
|
||||||
final password = generateWalletPassword();
|
final password = generateWalletPassword();
|
||||||
|
String? passphrase;
|
||||||
|
DerivationInfo? derivationInfo;
|
||||||
|
if (options != null) {
|
||||||
|
derivationInfo = options["derivationInfo"] as DerivationInfo?;
|
||||||
|
passphrase = options["passphrase"] as String?;
|
||||||
|
}
|
||||||
|
derivationInfo ??= getDefaultDerivation();
|
||||||
|
|
||||||
switch (restoreWallet.restoreMode) {
|
switch (restoreWallet.restoreMode) {
|
||||||
case WalletRestoreMode.keys:
|
case WalletRestoreMode.keys:
|
||||||
|
@ -89,20 +96,34 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
|
||||||
name: name,
|
name: name,
|
||||||
height: restoreWallet.height ?? 0,
|
height: restoreWallet.height ?? 0,
|
||||||
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||||
password: password);
|
password: password,
|
||||||
|
);
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
|
return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
|
||||||
name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password);
|
name: name,
|
||||||
|
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||||
|
password: password,
|
||||||
|
passphrase: passphrase,
|
||||||
|
derivationType: derivationInfo!.derivationType!,
|
||||||
|
derivationPath: derivationInfo.derivationPath!,
|
||||||
|
);
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
return bitcoinCash!.createBitcoinCashRestoreWalletFromSeedCredentials(
|
return bitcoinCash!.createBitcoinCashRestoreWalletFromSeedCredentials(
|
||||||
name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password);
|
name: name,
|
||||||
|
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||||
|
password: password,
|
||||||
|
);
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
return ethereum!.createEthereumRestoreWalletFromSeedCredentials(
|
return ethereum!.createEthereumRestoreWalletFromSeedCredentials(
|
||||||
name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password);
|
name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password);
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
return nano!.createNanoRestoreWalletFromSeedCredentials(
|
return nano!.createNanoRestoreWalletFromSeedCredentials(
|
||||||
name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password);
|
name: name,
|
||||||
|
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||||
|
password: password,
|
||||||
|
derivationType: derivationInfo!.derivationType!,
|
||||||
|
);
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
return polygon!.createPolygonRestoreWalletFromSeedCredentials(
|
return polygon!.createPolygonRestoreWalletFromSeedCredentials(
|
||||||
name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password);
|
name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password);
|
||||||
|
@ -118,7 +139,8 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<WalletBase> processFromRestoredWallet(WalletCredentials credentials, RestoredWallet restoreWallet) async {
|
Future<WalletBase> processFromRestoredWallet(
|
||||||
|
WalletCredentials credentials, RestoredWallet restoreWallet) async {
|
||||||
try {
|
try {
|
||||||
switch (restoreWallet.restoreMode) {
|
switch (restoreWallet.restoreMode) {
|
||||||
case WalletRestoreMode.keys:
|
case WalletRestoreMode.keys:
|
||||||
|
|
|
@ -423,7 +423,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
Object _credentials() {
|
Object _credentials() {
|
||||||
final priority = _settingsStore.priority[wallet.type];
|
final priority = _settingsStore.priority[wallet.type];
|
||||||
|
|
||||||
if (priority == null && wallet.type != WalletType.nano && wallet.type != WalletType.solana) {
|
if (priority == null && wallet.type != WalletType.nano && wallet.type != WalletType.banano && wallet.type != WalletType.solana) {
|
||||||
throw Exception('Priority is null for wallet type: ${wallet.type}');
|
throw Exception('Priority is null for wallet type: ${wallet.type}');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,9 +71,9 @@ abstract class WalletCreationVMBase with Store {
|
||||||
dirPath: dirPath,
|
dirPath: dirPath,
|
||||||
address: '',
|
address: '',
|
||||||
showIntroCakePayCard: (!walletCreationService.typeExists(type)) && type != WalletType.haven,
|
showIntroCakePayCard: (!walletCreationService.typeExists(type)) && type != WalletType.haven,
|
||||||
derivationPath: credentials.derivationPath,
|
derivationInfo: credentials.derivationInfo ?? getDefaultDerivation(),
|
||||||
derivationType: credentials.derivationType,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
credentials.walletInfo = walletInfo;
|
credentials.walletInfo = walletInfo;
|
||||||
final wallet = restoreWallet != null
|
final wallet = restoreWallet != null
|
||||||
? await processFromRestoredWallet(credentials, restoreWallet)
|
? await processFromRestoredWallet(credentials, restoreWallet)
|
||||||
|
@ -89,6 +89,48 @@ abstract class WalletCreationVMBase with Store {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DerivationInfo? getDefaultDerivation() {
|
||||||
|
switch (this.type) {
|
||||||
|
case WalletType.nano:
|
||||||
|
return DerivationInfo(
|
||||||
|
derivationType: DerivationType.nano,
|
||||||
|
);
|
||||||
|
case WalletType.bitcoin:
|
||||||
|
case WalletType.litecoin:
|
||||||
|
return DerivationInfo(
|
||||||
|
derivationType: DerivationType.electrum,
|
||||||
|
derivationPath: "m/0'/0",
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DerivationInfo? getCommonRestoreDerivation() {
|
||||||
|
switch (this.type) {
|
||||||
|
case WalletType.nano:
|
||||||
|
return DerivationInfo(
|
||||||
|
derivationType: DerivationType.nano,
|
||||||
|
);
|
||||||
|
case WalletType.bitcoin:
|
||||||
|
return DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/84'/0'/0'/0",
|
||||||
|
description: "Standard BIP84 native segwit",
|
||||||
|
scriptType: "p2wpkh",
|
||||||
|
);
|
||||||
|
case WalletType.litecoin:
|
||||||
|
return DerivationInfo(
|
||||||
|
derivationType: DerivationType.bip39,
|
||||||
|
derivationPath: "m/84'/2'/0'/0",
|
||||||
|
description: "Standard BIP84 native segwit (litecoin)",
|
||||||
|
scriptType: "p2wpkh",
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WalletCredentials getCredentials(dynamic options) => throw UnimplementedError();
|
WalletCredentials getCredentials(dynamic options) => throw UnimplementedError();
|
||||||
|
|
||||||
Future<WalletBase> process(WalletCredentials credentials) => throw UnimplementedError();
|
Future<WalletBase> process(WalletCredentials credentials) => throw UnimplementedError();
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cake_wallet/di.dart';
|
import 'package:cake_wallet/di.dart';
|
||||||
import 'package:cake_wallet/nano/nano.dart';
|
import 'package:cake_wallet/nano/nano.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
|
import 'package:cw_core/nano_account_info_response.dart';
|
||||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||||
import 'package:cake_wallet/polygon/polygon.dart';
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/solana/solana.dart';
|
import 'package:cake_wallet/solana/solana.dart';
|
||||||
|
@ -66,6 +67,8 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||||
final bool hasBlockchainHeightLanguageSelector;
|
final bool hasBlockchainHeightLanguageSelector;
|
||||||
final bool hasRestoreFromPrivateKey;
|
final bool hasRestoreFromPrivateKey;
|
||||||
|
|
||||||
|
bool get hasPassphrase => [WalletType.bitcoin, WalletType.litecoin].contains(type);
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
WalletRestoreMode mode;
|
WalletRestoreMode mode;
|
||||||
|
|
||||||
|
@ -75,10 +78,10 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||||
@override
|
@override
|
||||||
WalletCredentials getCredentials(dynamic options) {
|
WalletCredentials getCredentials(dynamic options) {
|
||||||
final password = generateWalletPassword();
|
final password = generateWalletPassword();
|
||||||
|
String? passphrase = options['passphrase'] as String?;
|
||||||
final height = options['height'] as int? ?? 0;
|
final height = options['height'] as int? ?? 0;
|
||||||
name = options['name'] as String;
|
name = options['name'] as String;
|
||||||
DerivationType? derivationType = options["derivationType"] as DerivationType?;
|
DerivationInfo? derivationInfo = options["derivationInfo"] as DerivationInfo?;
|
||||||
String? derivationPath = options["derivationPath"] as String?;
|
|
||||||
|
|
||||||
if (mode == WalletRestoreMode.seed) {
|
if (mode == WalletRestoreMode.seed) {
|
||||||
final seed = options['seed'] as String;
|
final seed = options['seed'] as String;
|
||||||
|
@ -87,14 +90,15 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||||
return monero!.createMoneroRestoreWalletFromSeedCredentials(
|
return monero!.createMoneroRestoreWalletFromSeedCredentials(
|
||||||
name: name, height: height, mnemonic: seed, password: password);
|
name: name, height: height, mnemonic: seed, password: password);
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
|
case WalletType.litecoin:
|
||||||
return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
|
return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
|
||||||
name: name,
|
name: name,
|
||||||
mnemonic: seed,
|
mnemonic: seed,
|
||||||
password: password,
|
password: password,
|
||||||
|
passphrase: passphrase,
|
||||||
|
derivationType: derivationInfo!.derivationType!,
|
||||||
|
derivationPath: derivationInfo.derivationPath!,
|
||||||
);
|
);
|
||||||
case WalletType.litecoin:
|
|
||||||
return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
|
|
||||||
name: name, mnemonic: seed, password: password);
|
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
return haven!.createHavenRestoreWalletFromSeedCredentials(
|
return haven!.createHavenRestoreWalletFromSeedCredentials(
|
||||||
name: name, height: height, mnemonic: seed, password: password);
|
name: name, height: height, mnemonic: seed, password: password);
|
||||||
|
@ -106,7 +110,11 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||||
name: name, mnemonic: seed, password: password);
|
name: name, mnemonic: seed, password: password);
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
return nano!.createNanoRestoreWalletFromSeedCredentials(
|
return nano!.createNanoRestoreWalletFromSeedCredentials(
|
||||||
name: name, mnemonic: seed, password: password, derivationType: derivationType);
|
name: name,
|
||||||
|
mnemonic: seed,
|
||||||
|
password: password,
|
||||||
|
derivationType: derivationInfo!.derivationType!,
|
||||||
|
);
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
return polygon!.createPolygonRestoreWalletFromSeedCredentials(
|
return polygon!.createPolygonRestoreWalletFromSeedCredentials(
|
||||||
name: name,
|
name: name,
|
||||||
|
@ -185,23 +193,34 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||||
throw Exception('Unexpected type: ${type.toString()}');
|
throw Exception('Unexpected type: ${type.toString()}');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<DerivationType>> getDerivationTypes(dynamic options) async {
|
Future<List<DerivationInfo>> getDerivationInfo(dynamic credentials) async {
|
||||||
final seedKey = options['private_key'] as String?;
|
var list = <DerivationInfo>[];
|
||||||
final mnemonic = options['seed'] as String?;
|
var walletType = credentials["walletType"] as WalletType;
|
||||||
WalletType walletType = options['walletType'] as WalletType;
|
|
||||||
var appStore = getIt.get<AppStore>();
|
var appStore = getIt.get<AppStore>();
|
||||||
var node = appStore.settingsStore.getCurrentNode(walletType);
|
var node = appStore.settingsStore.getCurrentNode(walletType);
|
||||||
|
|
||||||
switch (type) {
|
switch (walletType) {
|
||||||
|
case WalletType.bitcoin:
|
||||||
|
case WalletType.litecoin:
|
||||||
|
String? mnemonic = credentials['seed'] as String?;
|
||||||
|
String? passphrase = credentials['passphrase'] as String?;
|
||||||
|
return bitcoin!.getDerivationsFromMnemonic(
|
||||||
|
mnemonic: mnemonic!,
|
||||||
|
node: node,
|
||||||
|
passphrase: passphrase,
|
||||||
|
);
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
return nanoUtil!
|
String? mnemonic = credentials['seed'] as String?;
|
||||||
.compareDerivationMethods(mnemonic: mnemonic, privateKey: seedKey, node: node);
|
String? seedKey = credentials['private_key'] as String?;
|
||||||
|
return nanoUtil!.getDerivationsFromMnemonic(
|
||||||
|
mnemonic: mnemonic,
|
||||||
|
seedKey: seedKey,
|
||||||
|
node: node,
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return list;
|
||||||
// throw Exception('Unexpected type: ${type.toString()}');
|
|
||||||
return [DerivationType.def];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -209,7 +228,6 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||||
if (mode == WalletRestoreMode.keys) {
|
if (mode == WalletRestoreMode.keys) {
|
||||||
return walletCreationService.restoreFromKeys(credentials, isTestnet: useTestnet);
|
return walletCreationService.restoreFromKeys(credentials, isTestnet: useTestnet);
|
||||||
}
|
}
|
||||||
|
|
||||||
return walletCreationService.restoreFromSeed(credentials, isTestnet: useTestnet);
|
return walletCreationService.restoreFromSeed(credentials, isTestnet: useTestnet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "المخرجات",
|
"outputs": "المخرجات",
|
||||||
"overwrite_amount": "تغير المبلغ",
|
"overwrite_amount": "تغير المبلغ",
|
||||||
"pairingInvalidEvent": "ﺢﻟﺎﺻ ﺮﻴﻏ ﺙﺪﺣ ﻥﺍﺮﻗﺇ",
|
"pairingInvalidEvent": "ﺢﻟﺎﺻ ﺮﻴﻏ ﺙﺪﺣ ﻥﺍﺮﻗﺇ",
|
||||||
|
"passphrase": "عبارة الممر (اختياري)",
|
||||||
"password": "كلمة المرور",
|
"password": "كلمة المرور",
|
||||||
"paste": "لصق",
|
"paste": "لصق",
|
||||||
"pause_wallet_creation": ".ﺎﻴًﻟﺎﺣ ﺎﺘًﻗﺆﻣ ﺔﻔﻗﻮﺘﻣ Haven Wallet ءﺎﺸﻧﺇ ﻰﻠﻋ ﺓﺭﺪﻘﻟﺍ",
|
"pause_wallet_creation": ".ﺎﻴًﻟﺎﺣ ﺎﺘًﻗﺆﻣ ﺔﻔﻗﻮﺘﻣ Haven Wallet ءﺎﺸﻧﺇ ﻰﻠﻋ ﺓﺭﺪﻘﻟﺍ",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "Изходи",
|
"outputs": "Изходи",
|
||||||
"overwrite_amount": "Промени сума",
|
"overwrite_amount": "Промени сума",
|
||||||
"pairingInvalidEvent": "Невалидно събитие при сдвояване",
|
"pairingInvalidEvent": "Невалидно събитие при сдвояване",
|
||||||
|
"passphrase": "Passphrase (по избор)",
|
||||||
"password": "Парола",
|
"password": "Парола",
|
||||||
"paste": "Поставяне",
|
"paste": "Поставяне",
|
||||||
"pause_wallet_creation": "Възможността за създаване на Haven Wallet в момента е на пауза.",
|
"pause_wallet_creation": "Възможността за създаване на Haven Wallet в момента е на пауза.",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "Výstupy",
|
"outputs": "Výstupy",
|
||||||
"overwrite_amount": "Přepsat částku",
|
"overwrite_amount": "Přepsat částku",
|
||||||
"pairingInvalidEvent": "Neplatná událost párování",
|
"pairingInvalidEvent": "Neplatná událost párování",
|
||||||
|
"passphrase": "Passphrase (volitelné)",
|
||||||
"password": "Heslo",
|
"password": "Heslo",
|
||||||
"paste": "Vložit",
|
"paste": "Vložit",
|
||||||
"pause_wallet_creation": "Možnost vytvářet Haven Wallet je momentálně pozastavena.",
|
"pause_wallet_creation": "Možnost vytvářet Haven Wallet je momentálně pozastavena.",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "Ausgänge",
|
"outputs": "Ausgänge",
|
||||||
"overwrite_amount": "Overwrite amount",
|
"overwrite_amount": "Overwrite amount",
|
||||||
"pairingInvalidEvent": "Paarung ungültiges Ereignis",
|
"pairingInvalidEvent": "Paarung ungültiges Ereignis",
|
||||||
|
"passphrase": "Passphrase (optional)",
|
||||||
"password": "Passwort",
|
"password": "Passwort",
|
||||||
"paste": "Einfügen",
|
"paste": "Einfügen",
|
||||||
"pause_wallet_creation": "Die Möglichkeit, Haven Wallet zu erstellen, ist derzeit pausiert.",
|
"pause_wallet_creation": "Die Möglichkeit, Haven Wallet zu erstellen, ist derzeit pausiert.",
|
||||||
|
@ -425,8 +426,8 @@
|
||||||
"placeholder_transactions": "Ihre Transaktionen werden hier angezeigt",
|
"placeholder_transactions": "Ihre Transaktionen werden hier angezeigt",
|
||||||
"please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist",
|
"please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist",
|
||||||
"please_make_selection": "Bitte treffen Sie unten eine Auswahl zum Erstellen oder Wiederherstellen Ihrer Wallet.",
|
"please_make_selection": "Bitte treffen Sie unten eine Auswahl zum Erstellen oder Wiederherstellen Ihrer Wallet.",
|
||||||
"Please_reference_document": "Weitere Informationen finden Sie in den Dokumenten unten.",
|
|
||||||
"please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.",
|
"please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.",
|
||||||
|
"Please_reference_document": "Weitere Informationen finden Sie in den Dokumenten unten.",
|
||||||
"please_select": "Bitte auswählen:",
|
"please_select": "Bitte auswählen:",
|
||||||
"please_select_backup_file": "Bitte wählen Sie die Sicherungsdatei und geben Sie das Sicherungskennwort ein.",
|
"please_select_backup_file": "Bitte wählen Sie die Sicherungsdatei und geben Sie das Sicherungskennwort ein.",
|
||||||
"please_try_to_connect_to_another_node": "Bitte versuchen Sie, sich mit einem anderen Knoten zu verbinden",
|
"please_try_to_connect_to_another_node": "Bitte versuchen Sie, sich mit einem anderen Knoten zu verbinden",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "Outputs",
|
"outputs": "Outputs",
|
||||||
"overwrite_amount": "Overwrite amount",
|
"overwrite_amount": "Overwrite amount",
|
||||||
"pairingInvalidEvent": "Pairing Invalid Event",
|
"pairingInvalidEvent": "Pairing Invalid Event",
|
||||||
|
"passphrase": "Passphrase (Optional)",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"paste": "Paste",
|
"paste": "Paste",
|
||||||
"pause_wallet_creation": "Ability to create Haven Wallet is currently paused.",
|
"pause_wallet_creation": "Ability to create Haven Wallet is currently paused.",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "Salidas",
|
"outputs": "Salidas",
|
||||||
"overwrite_amount": "Overwrite amount",
|
"overwrite_amount": "Overwrite amount",
|
||||||
"pairingInvalidEvent": "Evento de emparejamiento no válido",
|
"pairingInvalidEvent": "Evento de emparejamiento no válido",
|
||||||
|
"passphrase": "Passfrase (opcional)",
|
||||||
"password": "Contraseña",
|
"password": "Contraseña",
|
||||||
"paste": "Pegar",
|
"paste": "Pegar",
|
||||||
"pause_wallet_creation": "La capacidad para crear Haven Wallet está actualmente pausada.",
|
"pause_wallet_creation": "La capacidad para crear Haven Wallet está actualmente pausada.",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "Les sorties",
|
"outputs": "Les sorties",
|
||||||
"overwrite_amount": "Remplacer le montant",
|
"overwrite_amount": "Remplacer le montant",
|
||||||
"pairingInvalidEvent": "Événement de couplage non valide",
|
"pairingInvalidEvent": "Événement de couplage non valide",
|
||||||
|
"passphrase": "Phrase de passe (facultative)",
|
||||||
"password": "Mot de passe",
|
"password": "Mot de passe",
|
||||||
"paste": "Coller",
|
"paste": "Coller",
|
||||||
"pause_wallet_creation": "La possibilité de créer Haven Wallet est actuellement suspendue.",
|
"pause_wallet_creation": "La possibilité de créer Haven Wallet est actuellement suspendue.",
|
||||||
|
|
|
@ -413,6 +413,7 @@
|
||||||
"outputs": "Abubuwan fashewa",
|
"outputs": "Abubuwan fashewa",
|
||||||
"overwrite_amount": "Rubuta adadin",
|
"overwrite_amount": "Rubuta adadin",
|
||||||
"pairingInvalidEvent": "Haɗa Lamarin mara inganci",
|
"pairingInvalidEvent": "Haɗa Lamarin mara inganci",
|
||||||
|
"passphrase": "Passphrase (Zabi)",
|
||||||
"password": "Kalmar wucewa",
|
"password": "Kalmar wucewa",
|
||||||
"paste": "Manna",
|
"paste": "Manna",
|
||||||
"pause_wallet_creation": "A halin yanzu an dakatar da ikon ƙirƙirar Haven Wallet.",
|
"pause_wallet_creation": "A halin yanzu an dakatar da ikon ƙirƙirar Haven Wallet.",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "आउटपुट",
|
"outputs": "आउटपुट",
|
||||||
"overwrite_amount": "Overwrite amount",
|
"overwrite_amount": "Overwrite amount",
|
||||||
"pairingInvalidEvent": "अमान्य ईवेंट युग्मित करना",
|
"pairingInvalidEvent": "अमान्य ईवेंट युग्मित करना",
|
||||||
|
"passphrase": "पासफ्रेज़ (वैकल्पिक)",
|
||||||
"password": "पारण शब्द",
|
"password": "पारण शब्द",
|
||||||
"paste": "पेस्ट करें",
|
"paste": "पेस्ट करें",
|
||||||
"pause_wallet_creation": "हेवन वॉलेट बनाने की क्षमता फिलहाल रुकी हुई है।",
|
"pause_wallet_creation": "हेवन वॉलेट बनाने की क्षमता फिलहाल रुकी हुई है।",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "Izlazi",
|
"outputs": "Izlazi",
|
||||||
"overwrite_amount": "Overwrite amount",
|
"overwrite_amount": "Overwrite amount",
|
||||||
"pairingInvalidEvent": "Nevažeći događaj uparivanja",
|
"pairingInvalidEvent": "Nevažeći događaj uparivanja",
|
||||||
|
"passphrase": "Prolaznica (neobavezno)",
|
||||||
"password": "Lozinka",
|
"password": "Lozinka",
|
||||||
"paste": "Zalijepi",
|
"paste": "Zalijepi",
|
||||||
"pause_wallet_creation": "Mogućnost stvaranja novčanika Haven trenutno je pauzirana.",
|
"pause_wallet_creation": "Mogućnost stvaranja novčanika Haven trenutno je pauzirana.",
|
||||||
|
|
|
@ -413,6 +413,7 @@
|
||||||
"outputs": "Output",
|
"outputs": "Output",
|
||||||
"overwrite_amount": "Timpa jumlah",
|
"overwrite_amount": "Timpa jumlah",
|
||||||
"pairingInvalidEvent": "Menyandingkan Acara Tidak Valid",
|
"pairingInvalidEvent": "Menyandingkan Acara Tidak Valid",
|
||||||
|
"passphrase": "Frasa sandi (opsional)",
|
||||||
"password": "Kata Sandi",
|
"password": "Kata Sandi",
|
||||||
"paste": "Tempel",
|
"paste": "Tempel",
|
||||||
"pause_wallet_creation": "Kemampuan untuk membuat Haven Wallet saat ini dijeda.",
|
"pause_wallet_creation": "Kemampuan untuk membuat Haven Wallet saat ini dijeda.",
|
||||||
|
|
|
@ -413,6 +413,7 @@
|
||||||
"outputs": "Output",
|
"outputs": "Output",
|
||||||
"overwrite_amount": "Sovrascrivi quantità",
|
"overwrite_amount": "Sovrascrivi quantità",
|
||||||
"pairingInvalidEvent": "Associazione evento non valido",
|
"pairingInvalidEvent": "Associazione evento non valido",
|
||||||
|
"passphrase": "Passphrase (opzionale)",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"paste": "Incolla",
|
"paste": "Incolla",
|
||||||
"pause_wallet_creation": "La possibilità di creare Haven Wallet è attualmente sospesa.",
|
"pause_wallet_creation": "La possibilità di creare Haven Wallet è attualmente sospesa.",
|
||||||
|
|
|
@ -412,6 +412,7 @@
|
||||||
"outputs": "出力",
|
"outputs": "出力",
|
||||||
"overwrite_amount": "Overwrite amount",
|
"overwrite_amount": "Overwrite amount",
|
||||||
"pairingInvalidEvent": "ペアリング無効イベント",
|
"pairingInvalidEvent": "ペアリング無効イベント",
|
||||||
|
"passphrase": "パスフレーズ(オプション)",
|
||||||
"password": "パスワード",
|
"password": "パスワード",
|
||||||
"paste": "ペースト",
|
"paste": "ペースト",
|
||||||
"pause_wallet_creation": "Haven Wallet を作成する機能は現在一時停止されています。",
|
"pause_wallet_creation": "Haven Wallet を作成する機能は現在一時停止されています。",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "출력",
|
"outputs": "출력",
|
||||||
"overwrite_amount": "Overwrite amount",
|
"overwrite_amount": "Overwrite amount",
|
||||||
"pairingInvalidEvent": "잘못된 이벤트 페어링",
|
"pairingInvalidEvent": "잘못된 이벤트 페어링",
|
||||||
|
"passphrase": "암호화 (선택 사항)",
|
||||||
"password": "암호",
|
"password": "암호",
|
||||||
"paste": "풀",
|
"paste": "풀",
|
||||||
"pause_wallet_creation": "Haven Wallet 생성 기능이 현재 일시 중지되었습니다.",
|
"pause_wallet_creation": "Haven Wallet 생성 기능이 현재 일시 중지되었습니다.",
|
||||||
|
@ -425,8 +426,8 @@
|
||||||
"placeholder_transactions": "거래가 여기에 표시됩니다",
|
"placeholder_transactions": "거래가 여기에 표시됩니다",
|
||||||
"please_fill_totp": "다른 기기에 있는 8자리 코드를 입력하세요.",
|
"please_fill_totp": "다른 기기에 있는 8자리 코드를 입력하세요.",
|
||||||
"please_make_selection": "아래에서 선택하십시오 지갑 만들기 또는 복구.",
|
"please_make_selection": "아래에서 선택하십시오 지갑 만들기 또는 복구.",
|
||||||
"please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.",
|
|
||||||
"Please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.",
|
"Please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.",
|
||||||
|
"please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.",
|
||||||
"please_select": "선택 해주세요:",
|
"please_select": "선택 해주세요:",
|
||||||
"please_select_backup_file": "백업 파일을 선택하고 백업 암호를 입력하십시오.",
|
"please_select_backup_file": "백업 파일을 선택하고 백업 암호를 입력하십시오.",
|
||||||
"please_try_to_connect_to_another_node": "다른 노드에 연결을 시도하십시오",
|
"please_try_to_connect_to_another_node": "다른 노드에 연결을 시도하십시오",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "ထုတ်လုပ်မှု",
|
"outputs": "ထုတ်လုပ်မှု",
|
||||||
"overwrite_amount": "ပမာဏကို ထပ်ရေးပါ။",
|
"overwrite_amount": "ပမာဏကို ထပ်ရေးပါ။",
|
||||||
"pairingInvalidEvent": "မမှန်ကန်သောဖြစ်ရပ်ကို တွဲချိတ်ခြင်း။",
|
"pairingInvalidEvent": "မမှန်ကန်သောဖြစ်ရပ်ကို တွဲချိတ်ခြင်း။",
|
||||||
|
"passphrase": "passphrase (optional)",
|
||||||
"password": "စကားဝှက်",
|
"password": "စကားဝှက်",
|
||||||
"paste": "ငါးပိ",
|
"paste": "ငါးပိ",
|
||||||
"pause_wallet_creation": "Haven Wallet ဖန်တီးနိုင်မှုကို လောလောဆယ် ခေတ္တရပ်ထားသည်။",
|
"pause_wallet_creation": "Haven Wallet ဖန်တီးနိုင်မှုကို လောလောဆယ် ခေတ္တရပ်ထားသည်။",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "Uitgangen",
|
"outputs": "Uitgangen",
|
||||||
"overwrite_amount": "Overwrite amount",
|
"overwrite_amount": "Overwrite amount",
|
||||||
"pairingInvalidEvent": "Koppelen Ongeldige gebeurtenis",
|
"pairingInvalidEvent": "Koppelen Ongeldige gebeurtenis",
|
||||||
|
"passphrase": "PassaspHRASE (optioneel)",
|
||||||
"password": "Wachtwoord",
|
"password": "Wachtwoord",
|
||||||
"paste": "Plakken",
|
"paste": "Plakken",
|
||||||
"pause_wallet_creation": "De mogelijkheid om Haven Wallet te maken is momenteel onderbroken.",
|
"pause_wallet_creation": "De mogelijkheid om Haven Wallet te maken is momenteel onderbroken.",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "Wyjścia",
|
"outputs": "Wyjścia",
|
||||||
"overwrite_amount": "Nadpisz ilość",
|
"overwrite_amount": "Nadpisz ilość",
|
||||||
"pairingInvalidEvent": "Nieprawidłowe zdarzenie parowania",
|
"pairingInvalidEvent": "Nieprawidłowe zdarzenie parowania",
|
||||||
|
"passphrase": "PassPhraza (opcjonalnie)",
|
||||||
"password": "Hasło",
|
"password": "Hasło",
|
||||||
"paste": "Wklej",
|
"paste": "Wklej",
|
||||||
"pause_wallet_creation": "Możliwość utworzenia Portfela Haven jest obecnie wstrzymana.",
|
"pause_wallet_creation": "Możliwość utworzenia Portfela Haven jest obecnie wstrzymana.",
|
||||||
|
|
|
@ -413,6 +413,7 @@
|
||||||
"outputs": "Saídas",
|
"outputs": "Saídas",
|
||||||
"overwrite_amount": "Overwrite amount",
|
"overwrite_amount": "Overwrite amount",
|
||||||
"pairingInvalidEvent": "Emparelhamento de evento inválido",
|
"pairingInvalidEvent": "Emparelhamento de evento inválido",
|
||||||
|
"passphrase": "Senha (opcional)",
|
||||||
"password": "Senha",
|
"password": "Senha",
|
||||||
"paste": "Colar",
|
"paste": "Colar",
|
||||||
"pause_wallet_creation": "A capacidade de criar a Haven Wallet está atualmente pausada.",
|
"pause_wallet_creation": "A capacidade de criar a Haven Wallet está atualmente pausada.",
|
||||||
|
|
|
@ -412,6 +412,7 @@
|
||||||
"outputs": "Выходы",
|
"outputs": "Выходы",
|
||||||
"overwrite_amount": "Overwrite amount",
|
"overwrite_amount": "Overwrite amount",
|
||||||
"pairingInvalidEvent": "Недействительное событие сопряжения",
|
"pairingInvalidEvent": "Недействительное событие сопряжения",
|
||||||
|
"passphrase": "Passfrase (необязательно)",
|
||||||
"password": "Пароль",
|
"password": "Пароль",
|
||||||
"paste": "Вставить",
|
"paste": "Вставить",
|
||||||
"pause_wallet_creation": "Возможность создания Haven Wallet в настоящее время приостановлена.",
|
"pause_wallet_creation": "Возможность создания Haven Wallet в настоящее время приостановлена.",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "เอาต์พุต",
|
"outputs": "เอาต์พุต",
|
||||||
"overwrite_amount": "เขียนทับจำนวน",
|
"overwrite_amount": "เขียนทับจำนวน",
|
||||||
"pairingInvalidEvent": "การจับคู่เหตุการณ์ที่ไม่ถูกต้อง",
|
"pairingInvalidEvent": "การจับคู่เหตุการณ์ที่ไม่ถูกต้อง",
|
||||||
|
"passphrase": "ข้อความรหัสผ่าน (ไม่บังคับ)",
|
||||||
"password": "รหัสผ่าน",
|
"password": "รหัสผ่าน",
|
||||||
"paste": "วาง",
|
"paste": "วาง",
|
||||||
"pause_wallet_creation": "ขณะนี้ความสามารถในการสร้าง Haven Wallet ถูกหยุดชั่วคราว",
|
"pause_wallet_creation": "ขณะนี้ความสามารถในการสร้าง Haven Wallet ถูกหยุดชั่วคราว",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "Mga output",
|
"outputs": "Mga output",
|
||||||
"overwrite_amount": "Overwrite na halaga",
|
"overwrite_amount": "Overwrite na halaga",
|
||||||
"pairingInvalidEvent": "Pagpares ng Di-wastong Kaganapan",
|
"pairingInvalidEvent": "Pagpares ng Di-wastong Kaganapan",
|
||||||
|
"passphrase": "Passphrase (opsyonal)",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"paste": "I -paste",
|
"paste": "I -paste",
|
||||||
"pause_wallet_creation": "Kasalukuyang naka-pause ang kakayahang gumawa ng Haven Wallet.",
|
"pause_wallet_creation": "Kasalukuyang naka-pause ang kakayahang gumawa ng Haven Wallet.",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "çıktılar",
|
"outputs": "çıktılar",
|
||||||
"overwrite_amount": "Miktarın üzerine yaz",
|
"overwrite_amount": "Miktarın üzerine yaz",
|
||||||
"pairingInvalidEvent": "Geçersiz Etkinliği Eşleştirme",
|
"pairingInvalidEvent": "Geçersiz Etkinliği Eşleştirme",
|
||||||
|
"passphrase": "Passfrase (isteğe bağlı)",
|
||||||
"password": "Parola",
|
"password": "Parola",
|
||||||
"paste": "Yapıştır",
|
"paste": "Yapıştır",
|
||||||
"pause_wallet_creation": "Haven Cüzdanı oluşturma yeteneği şu anda duraklatıldı.",
|
"pause_wallet_creation": "Haven Cüzdanı oluşturma yeteneği şu anda duraklatıldı.",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "Виходи",
|
"outputs": "Виходи",
|
||||||
"overwrite_amount": "Overwrite amount",
|
"overwrite_amount": "Overwrite amount",
|
||||||
"pairingInvalidEvent": "Недійсна подія сполучення",
|
"pairingInvalidEvent": "Недійсна подія сполучення",
|
||||||
|
"passphrase": "Пасофрази (необов’язково)",
|
||||||
"password": "Пароль",
|
"password": "Пароль",
|
||||||
"paste": "Вставити",
|
"paste": "Вставити",
|
||||||
"pause_wallet_creation": "Можливість створення гаманця Haven зараз призупинено.",
|
"pause_wallet_creation": "Можливість створення гаманця Haven зараз призупинено.",
|
||||||
|
|
|
@ -413,6 +413,7 @@
|
||||||
"outputs": "نتائج",
|
"outputs": "نتائج",
|
||||||
"overwrite_amount": "رقم کو اوور رائٹ کریں۔",
|
"overwrite_amount": "رقم کو اوور رائٹ کریں۔",
|
||||||
"pairingInvalidEvent": "ﭧﻧﻮﯾﺍ ﻂﻠﻏ ﺎﻧﺎﻨﺑ ﺍﮌﻮﺟ",
|
"pairingInvalidEvent": "ﭧﻧﻮﯾﺍ ﻂﻠﻏ ﺎﻧﺎﻨﺑ ﺍﮌﻮﺟ",
|
||||||
|
"passphrase": "پاسفریز (اختیاری)",
|
||||||
"password": "پاس ورڈ",
|
"password": "پاس ورڈ",
|
||||||
"paste": "چسپاں کریں۔",
|
"paste": "چسپاں کریں۔",
|
||||||
"pause_wallet_creation": "Haven Wallet ۔ﮯﮨ ﻑﻮﻗﻮﻣ ﻝﺎﺤﻟﺍ ﯽﻓ ﺖﯿﻠﮨﺍ ﯽﮐ ﮯﻧﺎﻨﺑ",
|
"pause_wallet_creation": "Haven Wallet ۔ﮯﮨ ﻑﻮﻗﻮﻣ ﻝﺎﺤﻟﺍ ﯽﻓ ﺖﯿﻠﮨﺍ ﯽﮐ ﮯﻧﺎﻨﺑ",
|
||||||
|
|
|
@ -412,6 +412,7 @@
|
||||||
"outputs": "Awọn iṣan",
|
"outputs": "Awọn iṣan",
|
||||||
"overwrite_amount": "Pààrọ̀ iye owó",
|
"overwrite_amount": "Pààrọ̀ iye owó",
|
||||||
"pairingInvalidEvent": "Pipọpọ Iṣẹlẹ Ti ko tọ",
|
"pairingInvalidEvent": "Pipọpọ Iṣẹlẹ Ti ko tọ",
|
||||||
|
"passphrase": "Ọrọ kukuru (iyan)",
|
||||||
"password": "Ọ̀rọ̀ aṣínà",
|
"password": "Ọ̀rọ̀ aṣínà",
|
||||||
"paste": "Fikún ẹ̀dà yín",
|
"paste": "Fikún ẹ̀dà yín",
|
||||||
"pause_wallet_creation": "Agbara lati ṣẹda Haven Wallet ti wa ni idaduro lọwọlọwọ.",
|
"pause_wallet_creation": "Agbara lati ṣẹda Haven Wallet ti wa ni idaduro lọwọlọwọ.",
|
||||||
|
|
|
@ -411,6 +411,7 @@
|
||||||
"outputs": "输出",
|
"outputs": "输出",
|
||||||
"overwrite_amount": "Overwrite amount",
|
"overwrite_amount": "Overwrite amount",
|
||||||
"pairingInvalidEvent": "配对无效事件",
|
"pairingInvalidEvent": "配对无效事件",
|
||||||
|
"passphrase": "密码(可选)",
|
||||||
"password": "密码",
|
"password": "密码",
|
||||||
"paste": "粘贴",
|
"paste": "粘贴",
|
||||||
"pause_wallet_creation": "创建 Haven 钱包的功能当前已暂停。",
|
"pause_wallet_creation": "创建 Haven 钱包的功能当前已暂停。",
|
||||||
|
|
|
@ -61,6 +61,8 @@ Future<void> main(List<String> args) async {
|
||||||
Future<void> generateBitcoin(bool hasImplementation) async {
|
Future<void> generateBitcoin(bool hasImplementation) async {
|
||||||
final outputFile = File(bitcoinOutputPath);
|
final outputFile = File(bitcoinOutputPath);
|
||||||
const bitcoinCommonHeaders = """
|
const bitcoinCommonHeaders = """
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:cw_core/node.dart';
|
||||||
import 'package:cw_core/pending_transaction.dart';
|
import 'package:cw_core/pending_transaction.dart';
|
||||||
import 'package:cw_core/receive_page_option.dart';
|
import 'package:cw_core/receive_page_option.dart';
|
||||||
import 'package:cw_core/unspent_transaction_output.dart';
|
import 'package:cw_core/unspent_transaction_output.dart';
|
||||||
|
@ -73,8 +75,17 @@ import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:cake_wallet/view_model/send/output.dart';
|
import 'package:cake_wallet/view_model/send/output.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';""";
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
|
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as btc;
|
||||||
|
import 'package:bip32/bip32.dart' as bip32;
|
||||||
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
""";
|
||||||
const bitcoinCWHeaders = """
|
const bitcoinCWHeaders = """
|
||||||
|
import 'package:cw_bitcoin/utils.dart';
|
||||||
|
import 'package:cw_bitcoin/litecoin_network.dart';
|
||||||
|
import 'package:cw_bitcoin/electrum_derivations.dart';
|
||||||
|
import 'package:cw_bitcoin/electrum.dart';
|
||||||
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
|
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_receive_page_option.dart';
|
import 'package:cw_bitcoin/bitcoin_receive_page_option.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||||
|
@ -87,6 +98,7 @@ import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
|
import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
|
||||||
import 'package:cw_bitcoin/litecoin_wallet_service.dart';
|
import 'package:cw_bitcoin/litecoin_wallet_service.dart';
|
||||||
|
import 'package:cw_bitcoin/script_hash.dart';
|
||||||
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
|
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
""";
|
""";
|
||||||
|
@ -112,7 +124,14 @@ import 'package:mobx/mobx.dart';
|
||||||
abstract class Bitcoin {
|
abstract class Bitcoin {
|
||||||
TransactionPriority getMediumTransactionPriority();
|
TransactionPriority getMediumTransactionPriority();
|
||||||
|
|
||||||
WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password});
|
WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({
|
||||||
|
required String name,
|
||||||
|
required String mnemonic,
|
||||||
|
required String password,
|
||||||
|
required DerivationType derivationType,
|
||||||
|
required String derivationPath,
|
||||||
|
String? passphrase,
|
||||||
|
});
|
||||||
WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({required String name, required String password, required String wif, WalletInfo? walletInfo});
|
WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({required String name, required String password, required String wif, WalletInfo? walletInfo});
|
||||||
WalletCredentials createBitcoinNewWalletCredentials({required String name, WalletInfo? walletInfo});
|
WalletCredentials createBitcoinNewWalletCredentials({required String name, WalletInfo? walletInfo});
|
||||||
List<String> getWordList();
|
List<String> getWordList();
|
||||||
|
@ -147,7 +166,10 @@ abstract class Bitcoin {
|
||||||
TransactionPriority getLitecoinTransactionPriorityMedium();
|
TransactionPriority getLitecoinTransactionPriorityMedium();
|
||||||
TransactionPriority getBitcoinTransactionPrioritySlow();
|
TransactionPriority getBitcoinTransactionPrioritySlow();
|
||||||
TransactionPriority getLitecoinTransactionPrioritySlow();
|
TransactionPriority getLitecoinTransactionPrioritySlow();
|
||||||
|
Future<List<DerivationType>> compareDerivationMethods(
|
||||||
|
{required String mnemonic, required Node node});
|
||||||
|
Future<List<DerivationInfo>> getDerivationsFromMnemonic(
|
||||||
|
{required String mnemonic, required Node node, String? passphrase});
|
||||||
Future<void> setAddressType(Object wallet, dynamic option);
|
Future<void> setAddressType(Object wallet, dynamic option);
|
||||||
ReceivePageOption getSelectedAddressType(Object wallet);
|
ReceivePageOption getSelectedAddressType(Object wallet);
|
||||||
List<ReceivePageOption> getBitcoinReceivePageOptions();
|
List<ReceivePageOption> getBitcoinReceivePageOptions();
|
||||||
|
@ -838,14 +860,14 @@ abstract class Nano {
|
||||||
required String name,
|
required String name,
|
||||||
required String password,
|
required String password,
|
||||||
required String mnemonic,
|
required String mnemonic,
|
||||||
DerivationType? derivationType,
|
required DerivationType derivationType,
|
||||||
});
|
});
|
||||||
|
|
||||||
WalletCredentials createNanoRestoreWalletFromKeysCredentials({
|
WalletCredentials createNanoRestoreWalletFromKeysCredentials({
|
||||||
required String name,
|
required String name,
|
||||||
required String password,
|
required String password,
|
||||||
required String seedKey,
|
required String seedKey,
|
||||||
DerivationType? derivationType,
|
required DerivationType derivationType,
|
||||||
});
|
});
|
||||||
|
|
||||||
List<String> getNanoWordList(String language);
|
List<String> getNanoWordList(String language);
|
||||||
|
@ -892,6 +914,11 @@ abstract class NanoUtil {
|
||||||
String? privateKey,
|
String? privateKey,
|
||||||
required Node node,
|
required Node node,
|
||||||
});
|
});
|
||||||
|
Future<List<DerivationInfo>> getDerivationsFromMnemonic({
|
||||||
|
String? mnemonic,
|
||||||
|
String? seedKey,
|
||||||
|
required Node node,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue