commit
3dd1bdabcc
@ -1,6 +1,6 @@
|
||||
#Fri Jun 23 08:50:38 CEST 2017
|
||||
#Mon Apr 19 18:19:26 EEST 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
|
||||
|
@ -0,0 +1,33 @@
|
||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||
import 'package:cake_wallet/bitcoin/utils.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
|
||||
import 'package:cake_wallet/bitcoin/electrum_wallet_addresses.dart';
|
||||
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'bitcoin_wallet_addresses.g.dart';
|
||||
|
||||
class BitcoinWalletAddresses = BitcoinWalletAddressesBase
|
||||
with _$BitcoinWalletAddresses;
|
||||
|
||||
abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses
|
||||
with Store {
|
||||
BitcoinWalletAddressesBase(
|
||||
WalletInfo walletInfo,
|
||||
{@required List<BitcoinAddressRecord> initialAddresses,
|
||||
int accountIndex = 0,
|
||||
@required bitcoin.HDWallet hd,
|
||||
@required this.networkType})
|
||||
: super(
|
||||
walletInfo,
|
||||
initialAddresses: initialAddresses,
|
||||
accountIndex: accountIndex,
|
||||
hd: hd);
|
||||
|
||||
bitcoin.NetworkType networkType;
|
||||
|
||||
@override
|
||||
String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
|
||||
generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
|
||||
import 'package:cake_wallet/entities/wallet_addresses.dart';
|
||||
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'electrum_wallet_addresses.g.dart';
|
||||
|
||||
class ElectrumWalletAddresses = ElectrumWalletAddressesBase
|
||||
with _$ElectrumWalletAddresses;
|
||||
|
||||
abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||
ElectrumWalletAddressesBase(WalletInfo walletInfo,
|
||||
{@required List<BitcoinAddressRecord> initialAddresses,
|
||||
int accountIndex = 0,
|
||||
@required bitcoin.HDWallet hd})
|
||||
: super(walletInfo) {
|
||||
this.hd = hd;
|
||||
this.accountIndex = accountIndex;
|
||||
addresses = ObservableList<BitcoinAddressRecord>.of(
|
||||
(initialAddresses ?? []).toSet());
|
||||
}
|
||||
|
||||
@override
|
||||
@observable
|
||||
String address;
|
||||
|
||||
bitcoin.HDWallet hd;
|
||||
|
||||
ObservableList<BitcoinAddressRecord> addresses;
|
||||
|
||||
int accountIndex;
|
||||
|
||||
@override
|
||||
Future<void> init() async {
|
||||
await generateAddresses();
|
||||
address = addresses[accountIndex].address;
|
||||
await updateAddressesInBox();
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> nextAddress() async {
|
||||
accountIndex += 1;
|
||||
|
||||
if (accountIndex >= addresses.length) {
|
||||
accountIndex = 0;
|
||||
}
|
||||
|
||||
address = addresses[accountIndex].address;
|
||||
|
||||
await updateAddressesInBox();
|
||||
}
|
||||
|
||||
Future<void> generateAddresses() async {
|
||||
if (addresses.length < 33) {
|
||||
final addressesCount = 33 - addresses.length;
|
||||
await generateNewAddresses(addressesCount,
|
||||
startIndex: addresses.length, hd: hd);
|
||||
}
|
||||
}
|
||||
|
||||
Future<BitcoinAddressRecord> generateNewAddress(
|
||||
{bool isHidden = false, bitcoin.HDWallet hd}) async {
|
||||
accountIndex += 1;
|
||||
final _hd = hd ?? this.hd;
|
||||
final address = BitcoinAddressRecord(
|
||||
getAddress(index: accountIndex, hd: _hd),
|
||||
index: accountIndex,
|
||||
isHidden: isHidden);
|
||||
addresses.add(address);
|
||||
return address;
|
||||
}
|
||||
|
||||
Future<List<BitcoinAddressRecord>> generateNewAddresses(int count,
|
||||
{int startIndex = 0, bitcoin.HDWallet hd, bool isHidden = false}) async {
|
||||
final list = <BitcoinAddressRecord>[];
|
||||
|
||||
for (var i = startIndex; i < count + startIndex; i++) {
|
||||
final address = BitcoinAddressRecord(getAddress(index: i, hd: hd),
|
||||
index: i, isHidden: isHidden);
|
||||
list.add(address);
|
||||
}
|
||||
|
||||
addresses.addAll(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
/*Future<void> updateAddress(String address) async {
|
||||
for (final addr in addresses) {
|
||||
if (addr.address == address) {
|
||||
await save();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
String getAddress({@required int index, @required bitcoin.HDWallet hd}) => '';
|
||||
|
||||
@override
|
||||
Future<void> updateAddressesInBox() async {
|
||||
try {
|
||||
addressesMap.clear();
|
||||
addressesMap[address] = '';
|
||||
|
||||
await saveAddressesInBox();
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_mnemonic.dart';
|
||||
import 'package:cake_wallet/bitcoin/utils.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
|
||||
import 'package:cake_wallet/bitcoin/electrum_wallet_addresses.dart';
|
||||
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'litecoin_wallet_addresses.g.dart';
|
||||
|
||||
class LitecoinWalletAddresses = LitecoinWalletAddressesBase
|
||||
with _$LitecoinWalletAddresses;
|
||||
|
||||
abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses
|
||||
with Store {
|
||||
LitecoinWalletAddressesBase(
|
||||
WalletInfo walletInfo,
|
||||
{@required List<BitcoinAddressRecord> initialAddresses,
|
||||
int accountIndex = 0,
|
||||
@required bitcoin.HDWallet hd,
|
||||
@required this.networkType,
|
||||
@required this.mnemonic})
|
||||
: super(
|
||||
walletInfo,
|
||||
initialAddresses: initialAddresses,
|
||||
accountIndex: accountIndex,
|
||||
hd: hd);
|
||||
|
||||
bitcoin.NetworkType networkType;
|
||||
|
||||
final String mnemonic;
|
||||
|
||||
@override
|
||||
String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
|
||||
generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
|
||||
|
||||
@override
|
||||
Future<void> generateAddresses() async {
|
||||
if (addresses.length < 33) {
|
||||
final addressesCount = 22 - addresses.length;
|
||||
await generateNewAddresses(addressesCount,
|
||||
hd: hd, startIndex: addresses.length);
|
||||
|
||||
final changeRoot = bitcoin.HDWallet.fromSeed(
|
||||
mnemonicToSeedBytes(mnemonic),
|
||||
network: networkType)
|
||||
.derivePath("m/0'/1");
|
||||
|
||||
await generateNewAddresses(11,
|
||||
startIndex: 0, hd: changeRoot, isHidden: true);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
import 'package:cake_wallet/entities/openalias_record.dart';
|
||||
import 'package:cake_wallet/entities/parsed_address.dart';
|
||||
import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
|
||||
|
||||
const topLevelDomain = 'crypto';
|
||||
|
||||
Future<ParsedAddress> parseAddressFromDomain(
|
||||
String domain, String ticker) async {
|
||||
try {
|
||||
final formattedName = OpenaliasRecord.formatDomainName(domain);
|
||||
final domainParts = formattedName.split('.');
|
||||
final name = domainParts.last;
|
||||
|
||||
if (domainParts.length <= 1 || domainParts.first.isEmpty || name.isEmpty) {
|
||||
return ParsedAddress(address: domain);
|
||||
}
|
||||
|
||||
if (name.contains(topLevelDomain)) {
|
||||
final address =
|
||||
await fetchUnstoppableDomainAddress(domain, ticker);
|
||||
|
||||
if (address?.isEmpty ?? true) {
|
||||
return ParsedAddress(address: domain);
|
||||
}
|
||||
|
||||
return ParsedAddress(
|
||||
address: address,
|
||||
name: domain,
|
||||
parseFrom: ParseFrom.unstoppableDomains);
|
||||
}
|
||||
|
||||
final record = await OpenaliasRecord.fetchAddressAndName(formattedName);
|
||||
|
||||
if (record == null || record.address.contains(formattedName)) {
|
||||
return ParsedAddress(address: domain);
|
||||
}
|
||||
|
||||
return ParsedAddress(
|
||||
address: record.address,
|
||||
name: record.name,
|
||||
parseFrom: ParseFrom.openAlias);
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
|
||||
return ParsedAddress(address: domain);
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
enum ParseFrom {unstoppableDomains, openAlias, notParsed}
|
||||
|
||||
class ParsedAddress {
|
||||
ParsedAddress({
|
||||
this.address = '',
|
||||
this.name = '',
|
||||
this.parseFrom = ParseFrom.notParsed});
|
||||
|
||||
final String address;
|
||||
final String name;
|
||||
final ParseFrom parseFrom;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
const channel = MethodChannel('com.cake_wallet/native_utils');
|
||||
|
||||
Future<String> fetchUnstoppableDomainAddress(String domain, String ticker) async {
|
||||
var address = '';
|
||||
|
||||
try {
|
||||
address = await channel.invokeMethod(
|
||||
'getUnstoppableDomainAddress',
|
||||
<String, String> {
|
||||
'domain' : domain,
|
||||
'ticker' : ticker
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
print('Unstoppable domain error: ${e.toString()}');
|
||||
address = '';
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||
|
||||
abstract class WalletAddresses {
|
||||
WalletAddresses(this.walletInfo) {
|
||||
addressesMap = {};
|
||||
}
|
||||
|
||||
final WalletInfo walletInfo;
|
||||
|
||||
String get address;
|
||||
|
||||
set address(String address);
|
||||
|
||||
Map<String, String> addressesMap;
|
||||
|
||||
Future<void> init();
|
||||
|
||||
Future<void> updateAddressesInBox();
|
||||
|
||||
Future<void> saveAddressesInBox() async {
|
||||
try {
|
||||
if (walletInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
walletInfo.address = address;
|
||||
walletInfo.addresses = addressesMap;
|
||||
|
||||
if (walletInfo.isInBox) {
|
||||
await walletInfo.save();
|
||||
}
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
import 'package:cake_wallet/entities/wallet_addresses.dart';
|
||||
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||
import 'package:cake_wallet/monero/account.dart';
|
||||
import 'package:cake_wallet/monero/monero_account_list.dart';
|
||||
import 'package:cake_wallet/monero/monero_subaddress_list.dart';
|
||||
import 'package:cake_wallet/monero/subaddress.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'monero_wallet_addresses.g.dart';
|
||||
|
||||
class MoneroWalletAddresses = MoneroWalletAddressesBase
|
||||
with _$MoneroWalletAddresses;
|
||||
|
||||
abstract class MoneroWalletAddressesBase extends WalletAddresses with Store {
|
||||
MoneroWalletAddressesBase(WalletInfo walletInfo) : super(walletInfo) {
|
||||
accountList = MoneroAccountList();
|
||||
subaddressList = MoneroSubaddressList();
|
||||
}
|
||||
|
||||
@override
|
||||
@observable
|
||||
String address;
|
||||
|
||||
@observable
|
||||
Account account;
|
||||
|
||||
@observable
|
||||
Subaddress subaddress;
|
||||
|
||||
MoneroSubaddressList subaddressList;
|
||||
|
||||
MoneroAccountList accountList;
|
||||
|
||||
@override
|
||||
Future<void> init() async {
|
||||
accountList.update();
|
||||
account = accountList.accounts.first;
|
||||
updateSubaddressList(accountIndex: account.id ?? 0);
|
||||
await updateAddressesInBox();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateAddressesInBox() async {
|
||||
try {
|
||||
final _subaddressList = MoneroSubaddressList();
|
||||
|
||||
addressesMap.clear();
|
||||
|
||||
accountList.accounts.forEach((account) {
|
||||
_subaddressList.update(accountIndex: account.id);
|
||||
_subaddressList.subaddresses.forEach((subaddress) {
|
||||
addressesMap[subaddress.address] = subaddress.label;
|
||||
});
|
||||
});
|
||||
|
||||
await saveAddressesInBox();
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
bool validate() {
|
||||
accountList.update();
|
||||
final accountListLength = accountList.accounts?.length ?? 0;
|
||||
|
||||
if (accountListLength <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
subaddressList.update(accountIndex: accountList.accounts.first.id);
|
||||
final subaddressListLength = subaddressList.subaddresses?.length ?? 0;
|
||||
|
||||
if (subaddressListLength <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void updateSubaddressList({int accountIndex}) {
|
||||
subaddressList.update(accountIndex: accountIndex);
|
||||
subaddress = subaddressList.subaddresses.first;
|
||||
address = subaddress.address;
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
import 'dart:io';
|
||||
import 'package:cake_wallet/entities/pathForWallet.dart';
|
||||
import 'package:cake_wallet/entities/wallet_type.dart';
|
||||
|
||||
String backupFileName(String originalPath) {
|
||||
final pathParts = originalPath.split('/');
|
||||
final newName = '#_${pathParts.last}';
|
||||
pathParts.removeLast();
|
||||
pathParts.add(newName);
|
||||
return pathParts.join('/');
|
||||
}
|
||||
|
||||
Future<void> backupWalletFiles(String name) async {
|
||||
final path = await pathForWallet(name: name, type: WalletType.monero);
|
||||
final cacheFile = File(path);
|
||||
final keysFile = File('$path.keys');
|
||||
final addressListFile = File('$path.address.txt');
|
||||
final newCacheFilePath = backupFileName(cacheFile.path);
|
||||
final newKeysFilePath = backupFileName(keysFile.path);
|
||||
final newAddressListFilePath = backupFileName(addressListFile.path);
|
||||
|
||||
if (cacheFile.existsSync()) {
|
||||
await cacheFile.copy(newCacheFilePath);
|
||||
}
|
||||
|
||||
if (keysFile.existsSync()) {
|
||||
await keysFile.copy(newKeysFilePath);
|
||||
}
|
||||
|
||||
if (addressListFile.existsSync()) {
|
||||
await addressListFile.copy(newAddressListFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> restoreWalletFiles(String name) async {
|
||||
final walletDirPath = await pathForWalletDir(name: name, type: WalletType.monero);
|
||||
final cacheFilePath = '$walletDirPath/$name';
|
||||
final keysFilePath = '$walletDirPath/$name.keys';
|
||||
final addressListFilePath = '$walletDirPath/$name.address.txt';
|
||||
final backupCacheFile = File(backupFileName(cacheFilePath));
|
||||
final backupKeysFile = File(backupFileName(keysFilePath));
|
||||
final backupAddressListFile = File(backupFileName(addressListFilePath));
|
||||
|
||||
if (backupCacheFile.existsSync()) {
|
||||
await backupCacheFile.copy(cacheFilePath);
|
||||
}
|
||||
|
||||
if (backupKeysFile.existsSync()) {
|
||||
await backupKeysFile.copy(keysFilePath);
|
||||
}
|
||||
|
||||
if (backupAddressListFile.existsSync()) {
|
||||
await backupAddressListFile.copy(addressListFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> backupWalletFilesExists(String name) async {
|
||||
final walletDirPath = await pathForWalletDir(name: name, type: WalletType.monero);
|
||||
final cacheFilePath = '$walletDirPath/$name';
|
||||
final keysFilePath = '$walletDirPath/$name.keys';
|
||||
final addressListFilePath = '$walletDirPath/$name.address.txt';
|
||||
final backupCacheFile = File(backupFileName(cacheFilePath));
|
||||
final backupKeysFile = File(backupFileName(keysFilePath));
|
||||
final backupAddressListFile = File(backupFileName(addressListFilePath));
|
||||
|
||||
return backupCacheFile.existsSync()
|
||||
&& backupKeysFile.existsSync()
|
||||
&& backupAddressListFile.existsSync();
|
||||
}
|
||||
|
||||
Future<void> removeCache(String name) async {
|
||||
final path = await pathForWallet(name: name, type: WalletType.monero);
|
||||
final cacheFile = File(path);
|
||||
|
||||
if (cacheFile.existsSync()) {
|
||||
cacheFile.deleteSync();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> restoreOrResetWalletFiles(String name) async {
|
||||
final backupsExists = await backupWalletFilesExists(name);
|
||||
|
||||
if (backupsExists) {
|
||||
await restoreWalletFiles(name);
|
||||
}
|
||||
|
||||
removeCache(name);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
void showAddressAlert(BuildContext context, String title, String content) async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
|
||||
return AlertWithOneAction(
|
||||
alertTitle: title,
|
||||
alertContent: content,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
}
|
Loading…
Reference in new issue