mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
Merge branch 'release-4.2.4' into CAKE-334-unspent-coins-control-application-logic
This commit is contained in:
commit
3dd1bdabcc
57 changed files with 956 additions and 333 deletions
|
@ -71,8 +71,9 @@ android {
|
|||
release {
|
||||
signingConfig signingConfigs.release
|
||||
|
||||
minifyEnabled true
|
||||
useProguard true
|
||||
shrinkResources false
|
||||
minifyEnabled false
|
||||
useProguard false
|
||||
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
|
@ -85,8 +86,9 @@ flutter {
|
|||
|
||||
dependencies {
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test:runner:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
|
||||
androidTestImplementation 'androidx.test:runner:1.3.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
implementation 'com.unstoppabledomains:resolution:1.13.0'
|
||||
implementation 'com.google.firebase:firebase-core:19.0.0'
|
||||
implementation 'com.google.firebase:firebase-messaging:19.0.0'
|
||||
}
|
||||
|
|
|
@ -10,14 +10,19 @@ import io.flutter.plugin.common.MethodCall;
|
|||
import io.flutter.plugin.common.MethodChannel;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import com.unstoppabledomains.resolution.DomainResolution;
|
||||
import com.unstoppabledomains.resolution.Resolution;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class MainActivity extends FlutterFragmentActivity {
|
||||
final String UTILS_CHANNEL = "com.cake_wallet/native_utils";
|
||||
|
||||
final int UNSTOPPABLE_DOMAIN_MIN_VERSION_SDK = 24;
|
||||
|
||||
@Override
|
||||
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
|
||||
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
||||
|
@ -33,17 +38,44 @@ public class MainActivity extends FlutterFragmentActivity {
|
|||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
|
||||
try {
|
||||
if (call.method.equals("sec_random")) {
|
||||
int count = call.argument("count");
|
||||
SecureRandom random = new SecureRandom();
|
||||
byte bytes[] = new byte[count];
|
||||
random.nextBytes(bytes);
|
||||
handler.post(() -> result.success(bytes));
|
||||
} else {
|
||||
handler.post(() -> result.notImplemented());
|
||||
switch (call.method) {
|
||||
case "sec_random":
|
||||
int count = call.argument("count");
|
||||
SecureRandom random = new SecureRandom();
|
||||
byte bytes[] = new byte[count];
|
||||
random.nextBytes(bytes);
|
||||
handler.post(() -> result.success(bytes));
|
||||
break;
|
||||
case "getUnstoppableDomainAddress":
|
||||
int version = Build.VERSION.SDK_INT;
|
||||
if (version >= UNSTOPPABLE_DOMAIN_MIN_VERSION_SDK) {
|
||||
getUnstoppableDomainAddress(call, result);
|
||||
} else {
|
||||
handler.post(() -> result.success(""));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
handler.post(() -> result.notImplemented());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
handler.post(() -> result.error("UNCAUGHT_ERROR", e.getMessage(), null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void getUnstoppableDomainAddress(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
|
||||
DomainResolution resolution = new Resolution();
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
String domain = call.argument("domain");
|
||||
String ticker = call.argument("ticker");
|
||||
|
||||
AsyncTask.execute(() -> {
|
||||
try {
|
||||
String address = resolution.getAddress(domain, ticker);
|
||||
handler.post(() -> result.success(address));
|
||||
} catch (Exception e) {
|
||||
System.out.println("Expected Address, but got " + e.getMessage());
|
||||
handler.post(() -> result.success(""));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ buildscript {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.4'
|
||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
||||
classpath 'com.google.gms:google-services:4.3.8'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Uncomment this line to define a global platform for your project
|
||||
platform :ios, '9.0'
|
||||
platform :ios, '11.0'
|
||||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
|
@ -36,6 +36,7 @@ target 'Runner' do
|
|||
|
||||
# Cake Wallet (Legacy)
|
||||
pod 'CryptoSwift'
|
||||
pod 'UnstoppableDomainsResolution', '~> 0.3.6'
|
||||
pod 'Firebase/Messaging', '6.33.0'
|
||||
end
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ PODS:
|
|||
- Flutter
|
||||
- MTBBarcodeScanner
|
||||
- SwiftProtobuf
|
||||
- BigInt (5.2.0)
|
||||
- connectivity (0.0.1):
|
||||
- Flutter
|
||||
- Reachability
|
||||
|
@ -59,6 +60,8 @@ PODS:
|
|||
- SwiftyGif
|
||||
- esys_flutter_share (0.0.1):
|
||||
- Flutter
|
||||
- EthereumAddress (1.3.0):
|
||||
- CryptoSwift (~> 1.0)
|
||||
- file_picker (0.0.1):
|
||||
- DKImagePickerController/PhotoGallery
|
||||
- Flutter
|
||||
|
@ -150,6 +153,10 @@ PODS:
|
|||
- Flutter
|
||||
- SwiftProtobuf (1.12.0)
|
||||
- SwiftyGif (5.3.0)
|
||||
- UnstoppableDomainsResolution (0.3.6):
|
||||
- BigInt
|
||||
- CryptoSwift (~> 1.0)
|
||||
- EthereumAddress (~> 1.3)
|
||||
- url_launcher (0.0.1):
|
||||
- Flutter
|
||||
- webview_flutter (0.0.1):
|
||||
|
@ -174,14 +181,17 @@ DEPENDENCIES:
|
|||
- permission_handler (from `.symlinks/plugins/permission_handler/ios`)
|
||||
- share (from `.symlinks/plugins/share/ios`)
|
||||
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
|
||||
- UnstoppableDomainsResolution (~> 0.3.6)
|
||||
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
|
||||
- webview_flutter (from `.symlinks/plugins/webview_flutter/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/CocoaPods/Specs.git:
|
||||
- BigInt
|
||||
- CryptoSwift
|
||||
- DKImagePickerController
|
||||
- DKPhotoGallery
|
||||
- EthereumAddress
|
||||
- Firebase
|
||||
- FirebaseCore
|
||||
- FirebaseCoreDiagnostics
|
||||
|
@ -198,6 +208,7 @@ SPEC REPOS:
|
|||
- SDWebImage
|
||||
- SwiftProtobuf
|
||||
- SwiftyGif
|
||||
- UnstoppableDomainsResolution
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
barcode_scan:
|
||||
|
@ -239,6 +250,7 @@ EXTERNAL SOURCES:
|
|||
|
||||
SPEC CHECKSUMS:
|
||||
barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479
|
||||
BigInt: f668a80089607f521586bbe29513d708491ef2f7
|
||||
connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467
|
||||
CryptoSwift: 093499be1a94b0cae36e6c26b70870668cb56060
|
||||
cw_monero: 78f369253cc913efc23db9cf6be81a11eaf40fe1
|
||||
|
@ -246,6 +258,7 @@ SPEC CHECKSUMS:
|
|||
DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d
|
||||
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
||||
esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4
|
||||
EthereumAddress: 39fe8e11cf04e4e9902b55ae653dbc4e0aee5f30
|
||||
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
|
||||
Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5
|
||||
firebase_core: 5d6a02f3d85acd5f8321c2d6d62877626a670659
|
||||
|
@ -273,9 +286,9 @@ SPEC CHECKSUMS:
|
|||
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
|
||||
SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699
|
||||
SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40
|
||||
UnstoppableDomainsResolution: 63abb84858d3e91eb838a5bfa6f7e3c0e0593f24
|
||||
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
|
||||
webview_flutter: 9f491a9b5a66f2573946a389b2677987b0ff8c0b
|
||||
|
||||
PODFILE CHECKSUM: f316539722a6f9dbb0d0f1065a27fa7ea38c6f88
|
||||
|
||||
COCOAPODS: 1.9.3
|
||||
COCOAPODS: 1.10.1
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import UIKit
|
||||
import Flutter
|
||||
import UnstoppableDomainsResolution
|
||||
|
||||
@UIApplicationMain
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
lazy var resolution : Resolution? = {
|
||||
return try? Resolution()
|
||||
}()
|
||||
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
|
@ -70,6 +75,27 @@ import Flutter
|
|||
}
|
||||
|
||||
result(secRandom(count: count))
|
||||
case "getUnstoppableDomainAddress":
|
||||
guard let args = call.arguments as? Dictionary<String, String>,
|
||||
let domain = args["domain"],
|
||||
let ticker = args["ticker"],
|
||||
let resolution = self?.resolution else {
|
||||
result(nil)
|
||||
return
|
||||
}
|
||||
|
||||
resolution.addr(domain: domain, ticker: ticker) { addrResult in
|
||||
var address : String = ""
|
||||
|
||||
switch addrResult {
|
||||
case .success(let returnValue):
|
||||
address = returnValue
|
||||
case .failure(let error):
|
||||
print("Expected Address, but got \(error)")
|
||||
}
|
||||
|
||||
result(address)
|
||||
}
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
|
|
|
@ -3,12 +3,12 @@ import 'package:hive/hive.dart';
|
|||
import 'package:mobx/mobx.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||
import 'package:cake_wallet/bitcoin/utils.dart';
|
||||
import 'package:cake_wallet/bitcoin/electrum_wallet_snapshot.dart';
|
||||
import 'package:cake_wallet/bitcoin/electrum_wallet.dart';
|
||||
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
|
||||
import 'package:cake_wallet/bitcoin/electrum_balance.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_wallet_addresses.dart';
|
||||
|
||||
part 'bitcoin_wallet.g.dart';
|
||||
|
||||
|
@ -30,8 +30,14 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
unspentCoinsInfo: unspentCoinsInfo,
|
||||
networkType: bitcoin.bitcoin,
|
||||
initialAddresses: initialAddresses,
|
||||
initialBalance: initialBalance,
|
||||
accountIndex: accountIndex);
|
||||
initialBalance: initialBalance) {
|
||||
walletAddresses = BitcoinWalletAddresses(
|
||||
walletInfo,
|
||||
initialAddresses: initialAddresses,
|
||||
accountIndex: accountIndex,
|
||||
hd: hd,
|
||||
networkType: networkType);
|
||||
}
|
||||
|
||||
static Future<BitcoinWallet> open({
|
||||
@required String name,
|
||||
|
@ -50,8 +56,4 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
initialBalance: snp.balance,
|
||||
accountIndex: snp.accountIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
|
||||
generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
|
||||
}
|
||||
|
|
33
lib/bitcoin/bitcoin_wallet_addresses.dart
Normal file
33
lib/bitcoin/bitcoin_wallet_addresses.dart
Normal file
|
@ -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);
|
||||
}
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
import 'dart:convert';
|
||||
import 'package:cake_wallet/bitcoin/unspent_coins_info.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cake_wallet/bitcoin/electrum_wallet_addresses.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:rxdart/subjects.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
@ -45,18 +46,14 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
|||
@required this.networkType,
|
||||
@required this.mnemonic,
|
||||
ElectrumClient electrumClient,
|
||||
int accountIndex = 0,
|
||||
ElectrumBalance initialBalance})
|
||||
: balance = initialBalance ??
|
||||
const ElectrumBalance(confirmed: 0, unconfirmed: 0),
|
||||
hd = bitcoin.HDWallet.fromSeed(mnemonicToSeedBytes(mnemonic),
|
||||
network: networkType)
|
||||
.derivePath("m/0'/0"),
|
||||
addresses = ObservableList<BitcoinAddressRecord>.of(
|
||||
(initialAddresses ?? []).toSet()),
|
||||
syncStatus = NotConnectedSyncStatus(),
|
||||
_password = password,
|
||||
_accountIndex = accountIndex,
|
||||
_feeRates = <int>[],
|
||||
_isTransactionUpdating = false,
|
||||
super(walletInfo) {
|
||||
|
@ -79,8 +76,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
|||
Box<UnspentCoinsInfo> unspentCoinsInfo;
|
||||
|
||||
@override
|
||||
@observable
|
||||
String address;
|
||||
ElectrumWalletAddresses walletAddresses;
|
||||
|
||||
@override
|
||||
@observable
|
||||
|
@ -90,9 +86,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
|||
@observable
|
||||
SyncStatus syncStatus;
|
||||
|
||||
ObservableList<BitcoinAddressRecord> addresses;
|
||||
|
||||
List<String> get scriptHashes => addresses
|
||||
List<String> get scriptHashes => walletAddresses.addresses
|
||||
.map((addr) => scriptHash(addr.address, networkType: networkType))
|
||||
.toList();
|
||||
|
||||
|
@ -110,74 +104,15 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
|||
final String _password;
|
||||
List<BitcoinUnspent> unspentCoins;
|
||||
List<int> _feeRates;
|
||||
int _accountIndex;
|
||||
Map<String, BehaviorSubject<Object>> _scripthashesUpdateSubject;
|
||||
bool _isTransactionUpdating;
|
||||
|
||||
Future<void> init() async {
|
||||
await generateAddresses();
|
||||
address = addresses[_accountIndex].address;
|
||||
await walletAddresses.init();
|
||||
await transactionHistory.init();
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> nextAddress() async {
|
||||
_accountIndex += 1;
|
||||
|
||||
if (_accountIndex >= addresses.length) {
|
||||
_accountIndex = 0;
|
||||
}
|
||||
|
||||
address = addresses[_accountIndex].address;
|
||||
|
||||
await save();
|
||||
}
|
||||
|
||||
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);
|
||||
await save();
|
||||
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);
|
||||
await save();
|
||||
return list;
|
||||
}
|
||||
|
||||
Future<void> updateAddress(String address) async {
|
||||
for (final addr in addresses) {
|
||||
if (addr.address == address) {
|
||||
await save();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
@override
|
||||
Future<void> startSync() async {
|
||||
|
@ -266,8 +201,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
|||
}
|
||||
|
||||
final txb = bitcoin.TransactionBuilder(network: networkType);
|
||||
final changeAddress = address;
|
||||
|
||||
final changeAddress = walletAddresses.address;
|
||||
var leftAmount = totalAmount;
|
||||
var totalInputAmount = 0;
|
||||
|
||||
|
@ -340,8 +274,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
|||
|
||||
String toJSON() => json.encode({
|
||||
'mnemonic': mnemonic,
|
||||
'account_index': _accountIndex.toString(),
|
||||
'addresses': addresses.map((addr) => addr.toJSON()).toList(),
|
||||
'account_index': walletAddresses.accountIndex.toString(),
|
||||
'addresses': walletAddresses.addresses.map((addr) => addr.toJSON()).toList(),
|
||||
'balance': balance?.toJSON()
|
||||
});
|
||||
|
||||
|
@ -413,13 +347,12 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
|||
} catch (_) {}
|
||||
}
|
||||
|
||||
String getAddress({@required int index, @required bitcoin.HDWallet hd}) => '';
|
||||
|
||||
Future<String> makePath() async =>
|
||||
pathForWallet(name: walletInfo.name, type: walletInfo.type);
|
||||
|
||||
Future<void> updateUnspent() async {
|
||||
final unspent = await Future.wait(addresses.map((address) => electrumClient
|
||||
final unspent = await Future.wait(walletAddresses
|
||||
.addresses.map((address) => electrumClient
|
||||
.getListUnspentWithAddress(address.address, networkType)
|
||||
.then((unspent) => unspent
|
||||
.map((unspent) => BitcoinUnspent.fromJSON(address, unspent)))));
|
||||
|
@ -491,7 +424,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
|||
{@required String hash, @required int height}) async {
|
||||
final tx = await electrumClient.getTransactionExpanded(hash: hash);
|
||||
return ElectrumTransactionInfo.fromElectrumVerbose(tx, walletInfo.type,
|
||||
height: height, addresses: addresses);
|
||||
height: height, addresses: walletAddresses.addresses);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
111
lib/bitcoin/electrum_wallet_addresses.dart
Normal file
111
lib/bitcoin/electrum_wallet_addresses.dart
Normal file
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_mnemonic.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
|
||||
import 'package:cake_wallet/bitcoin/unspent_coins_info.dart';
|
||||
import 'package:cake_wallet/bitcoin/litecoin_wallet_addresses.dart';
|
||||
import 'package:cake_wallet/entities/transaction_priority.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
@ -12,7 +11,6 @@ import 'package:cake_wallet/bitcoin/electrum_wallet.dart';
|
|||
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
|
||||
import 'package:cake_wallet/bitcoin/electrum_balance.dart';
|
||||
import 'package:cake_wallet/bitcoin/litecoin_network.dart';
|
||||
import 'package:cake_wallet/bitcoin/utils.dart';
|
||||
|
||||
part 'litecoin_wallet.g.dart';
|
||||
|
||||
|
@ -34,8 +32,15 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
unspentCoinsInfo: unspentCoinsInfo,
|
||||
networkType: litecoinNetwork,
|
||||
initialAddresses: initialAddresses,
|
||||
initialBalance: initialBalance,
|
||||
accountIndex: accountIndex);
|
||||
initialBalance: initialBalance) {
|
||||
walletAddresses = LitecoinWalletAddresses(
|
||||
walletInfo,
|
||||
initialAddresses: initialAddresses,
|
||||
accountIndex: accountIndex,
|
||||
hd: hd,
|
||||
networkType: networkType,
|
||||
mnemonic: mnemonic);
|
||||
}
|
||||
|
||||
static Future<LitecoinWallet> open({
|
||||
@required String name,
|
||||
|
@ -55,27 +60,6 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
accountIndex: snp.accountIndex);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
int feeRate(TransactionPriority priority) {
|
||||
if (priority is LitecoinTransactionPriority) {
|
||||
|
|
54
lib/bitcoin/litecoin_wallet_addresses.dart
Normal file
54
lib/bitcoin/litecoin_wallet_addresses.dart
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ abstract class BuyProvider {
|
|||
String get trackUrl;
|
||||
|
||||
WalletType get walletType => wallet.type;
|
||||
String get walletAddress => wallet.address;
|
||||
String get walletAddress => wallet.walletAddresses.address;
|
||||
String get walletId => wallet.id;
|
||||
|
||||
@override
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import 'package:cake_wallet/entities/balance.dart';
|
||||
import 'package:cake_wallet/entities/transaction_info.dart';
|
||||
import 'package:cake_wallet/entities/transaction_priority.dart';
|
||||
import 'package:cake_wallet/entities/wallet_addresses.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cake_wallet/entities/wallet_info.dart';
|
||||
import 'package:cake_wallet/core/pending_transaction.dart';
|
||||
import 'package:cake_wallet/core/transaction_history.dart';
|
||||
import 'package:cake_wallet/entities/currency_for_wallet_type.dart';
|
||||
import 'package:cake_wallet/entities/monero_transaction_priority.dart';
|
||||
import 'package:cake_wallet/entities/crypto_currency.dart';
|
||||
import 'package:cake_wallet/entities/sync_status.dart';
|
||||
import 'package:cake_wallet/entities/node.dart';
|
||||
|
@ -31,9 +31,9 @@ abstract class WalletBase<
|
|||
|
||||
String get name => walletInfo.name;
|
||||
|
||||
String get address;
|
||||
//String get address;
|
||||
|
||||
set address(String address);
|
||||
//set address(String address);
|
||||
|
||||
BalanceType get balance;
|
||||
|
||||
|
@ -45,6 +45,8 @@ abstract class WalletBase<
|
|||
|
||||
Object get keys;
|
||||
|
||||
WalletAddresses get walletAddresses;
|
||||
|
||||
HistoryType transactionHistory;
|
||||
|
||||
Future<void> connectToNode({@required Node node});
|
||||
|
|
|
@ -370,7 +370,8 @@ Future setup(
|
|||
getIt.registerFactoryParam<MoneroAccountEditOrCreateViewModel,
|
||||
AccountListItem, void>(
|
||||
(AccountListItem account, _) => MoneroAccountEditOrCreateViewModel(
|
||||
(getIt.get<AppStore>().wallet as MoneroWallet).accountList,
|
||||
(getIt.get<AppStore>().wallet as MoneroWallet).walletAddresses.accountList,
|
||||
wallet: getIt.get<AppStore>().wallet,
|
||||
accountListItem: account));
|
||||
|
||||
getIt.registerFactoryParam<MoneroAccountEditOrCreatePage, AccountListItem,
|
||||
|
|
47
lib/entities/parse_address_from_domain.dart
Normal file
47
lib/entities/parse_address_from_domain.dart
Normal file
|
@ -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);
|
||||
}
|
12
lib/entities/parsed_address.dart
Normal file
12
lib/entities/parsed_address.dart
Normal file
|
@ -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;
|
||||
}
|
22
lib/entities/unstoppable_domain_address.dart
Normal file
22
lib/entities/unstoppable_domain_address.dart
Normal file
|
@ -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;
|
||||
}
|
36
lib/entities/wallet_addresses.dart
Normal file
36
lib/entities/wallet_addresses.dart
Normal file
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -53,5 +53,8 @@ class WalletInfo extends HiveObject {
|
|||
@HiveField(8)
|
||||
String address;
|
||||
|
||||
@HiveField(10)
|
||||
Map<String, String> addresses;
|
||||
|
||||
DateTime get date => DateTime.fromMillisecondsSinceEpoch(timestamp);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ import 'package:cake_wallet/entities/transaction_priority.dart';
|
|||
import 'package:cake_wallet/monero/monero_amount_format.dart';
|
||||
import 'package:cake_wallet/monero/monero_transaction_creation_exception.dart';
|
||||
import 'package:cake_wallet/monero/monero_transaction_info.dart';
|
||||
import 'package:cake_wallet/monero/monero_wallet_addresses.dart';
|
||||
import 'package:cake_wallet/monero/monero_wallet_utils.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_monero/transaction_history.dart'
|
||||
|
@ -15,10 +17,7 @@ import 'package:cake_wallet/monero/pending_monero_transaction.dart';
|
|||
import 'package:cake_wallet/monero/monero_wallet_keys.dart';
|
||||
import 'package:cake_wallet/monero/monero_balance.dart';
|
||||
import 'package:cake_wallet/monero/monero_transaction_history.dart';
|
||||
import 'package:cake_wallet/monero/monero_subaddress_list.dart';
|
||||
import 'package:cake_wallet/monero/monero_account_list.dart';
|
||||
import 'package:cake_wallet/monero/account.dart';
|
||||
import 'package:cake_wallet/monero/subaddress.dart';
|
||||
import 'package:cake_wallet/core/pending_transaction.dart';
|
||||
import 'package:cake_wallet/core/wallet_base.dart';
|
||||
import 'package:cake_wallet/entities/sync_status.dart';
|
||||
|
@ -35,9 +34,7 @@ class MoneroWallet = MoneroWalletBase with _$MoneroWallet;
|
|||
abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||
MoneroTransactionHistory, MoneroTransactionInfo> with Store {
|
||||
MoneroWalletBase({WalletInfo walletInfo})
|
||||
: accountList = MoneroAccountList(),
|
||||
subaddressList = MoneroSubaddressList(),
|
||||
super(walletInfo) {
|
||||
: super(walletInfo) {
|
||||
transactionHistory = MoneroTransactionHistory();
|
||||
balance = MoneroBalance(
|
||||
fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
|
||||
|
@ -47,33 +44,26 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
_isSavingAfterSync = false;
|
||||
_isSavingAfterNewTransaction = false;
|
||||
_isTransactionUpdating = false;
|
||||
_onAccountChangeReaction = reaction((_) => account, (Account account) {
|
||||
walletAddresses = MoneroWalletAddresses(walletInfo);
|
||||
_onAccountChangeReaction = reaction((_) => walletAddresses.account,
|
||||
(Account account) {
|
||||
balance = MoneroBalance(
|
||||
fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
|
||||
unlockedBalance:
|
||||
monero_wallet.getUnlockedBalance(accountIndex: account.id));
|
||||
subaddressList.update(accountIndex: account.id);
|
||||
subaddress = subaddressList.subaddresses.first;
|
||||
address = subaddress.address;
|
||||
walletAddresses.updateSubaddressList(accountIndex: account.id);
|
||||
});
|
||||
}
|
||||
|
||||
static const int _autoAfterSyncSaveInterval = 60000;
|
||||
|
||||
@observable
|
||||
Account account;
|
||||
|
||||
@observable
|
||||
Subaddress subaddress;
|
||||
@override
|
||||
MoneroWalletAddresses walletAddresses;
|
||||
|
||||
@override
|
||||
@observable
|
||||
SyncStatus syncStatus;
|
||||
|
||||
@override
|
||||
@observable
|
||||
String address;
|
||||
|
||||
@override
|
||||
@observable
|
||||
MoneroBalance balance;
|
||||
|
@ -88,10 +78,6 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
publicSpendKey: monero_wallet.getPublicSpendKey(),
|
||||
publicViewKey: monero_wallet.getPublicViewKey());
|
||||
|
||||
final MoneroSubaddressList subaddressList;
|
||||
|
||||
final MoneroAccountList accountList;
|
||||
|
||||
SyncListener _listener;
|
||||
ReactionDisposer _onAccountChangeReaction;
|
||||
int _lastAutosaveTimestamp;
|
||||
|
@ -101,15 +87,11 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
int _lastSaveTimestamp;
|
||||
|
||||
Future<void> init() async {
|
||||
accountList.update();
|
||||
account = accountList.accounts.first;
|
||||
subaddressList.update(accountIndex: account.id ?? 0);
|
||||
subaddress = subaddressList.getAll().first;
|
||||
await walletAddresses.init();
|
||||
balance = MoneroBalance(
|
||||
fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
|
||||
fullBalance: monero_wallet.getFullBalance(accountIndex: walletAddresses.account.id),
|
||||
unlockedBalance:
|
||||
monero_wallet.getUnlockedBalance(accountIndex: account.id));
|
||||
address = subaddress.address;
|
||||
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account.id));
|
||||
_setListeners();
|
||||
await updateTransactions();
|
||||
|
||||
|
@ -129,24 +111,6 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
_onAccountChangeReaction?.reaction?.dispose();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> connectToNode({@required Node node}) async {
|
||||
try {
|
||||
|
@ -189,7 +153,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
? moneroParseAmount(amount: _credentials.amount)
|
||||
: null;
|
||||
final unlockedBalance =
|
||||
monero_wallet.getUnlockedBalance(accountIndex: account.id);
|
||||
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account.id);
|
||||
|
||||
if ((amount != null && unlockedBalance < amount) ||
|
||||
(amount == null && unlockedBalance <= 0)) {
|
||||
|
@ -209,7 +173,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
paymentId: _credentials.paymentId,
|
||||
amount: _credentials.amount,
|
||||
priorityRaw: _credentials.priority.serialize(),
|
||||
accountIndex: account.id);
|
||||
accountIndex: walletAddresses.account.id);
|
||||
|
||||
return PendingMoneroTransaction(pendingTransactionDescription);
|
||||
}
|
||||
|
@ -238,12 +202,15 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
|
||||
@override
|
||||
Future<void> save() async {
|
||||
await walletAddresses.updateAddressesInBox();
|
||||
|
||||
final now = DateTime.now().millisecondsSinceEpoch;
|
||||
|
||||
if (now - _lastSaveTimestamp < Duration(seconds: 10).inMilliseconds) {
|
||||
return;
|
||||
}
|
||||
|
||||
await backupWalletFiles(name);
|
||||
_lastSaveTimestamp = now;
|
||||
await monero_wallet.store();
|
||||
}
|
||||
|
@ -265,7 +232,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
monero_wallet.rescanBlockchainAsync();
|
||||
await startSync();
|
||||
_askForUpdateBalance();
|
||||
accountList.update();
|
||||
walletAddresses.accountList.update();
|
||||
await _askForUpdateTransactionHistory();
|
||||
await save();
|
||||
await walletInfo.save();
|
||||
|
@ -364,10 +331,10 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
await updateTransactions();
|
||||
|
||||
int _getFullBalance() =>
|
||||
monero_wallet.getFullBalance(accountIndex: account.id);
|
||||
monero_wallet.getFullBalance(accountIndex: walletAddresses.account.id);
|
||||
|
||||
int _getUnlockedBalance() =>
|
||||
monero_wallet.getUnlockedBalance(accountIndex: account.id);
|
||||
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account.id);
|
||||
|
||||
Future<void> _afterSyncSave() async {
|
||||
try {
|
||||
|
@ -414,13 +381,13 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
if (walletInfo.isRecovery) {
|
||||
await _askForUpdateTransactionHistory();
|
||||
_askForUpdateBalance();
|
||||
accountList.update();
|
||||
walletAddresses.accountList.update();
|
||||
}
|
||||
|
||||
if (blocksLeft < 100) {
|
||||
await _askForUpdateTransactionHistory();
|
||||
_askForUpdateBalance();
|
||||
accountList.update();
|
||||
walletAddresses.accountList.update();
|
||||
syncStatus = SyncedSyncStatus();
|
||||
await _afterSyncSave();
|
||||
|
||||
|
|
85
lib/monero/monero_wallet_addresses.dart
Normal file
85
lib/monero/monero_wallet_addresses.dart
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:io';
|
||||
import 'package:cake_wallet/core/wallet_base.dart';
|
||||
import 'package:cake_wallet/monero/monero_wallet_utils.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cw_monero/wallet_manager.dart' as monero_wallet_manager;
|
||||
import 'package:cw_monero/wallet.dart' as monero_wallet;
|
||||
|
@ -55,16 +56,7 @@ class MoneroWalletService extends WalletService<
|
|||
MoneroWalletService(this.walletInfoSource);
|
||||
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
|
||||
static Future<void> _removeCache(String name) async {
|
||||
final path = await pathForWallet(name: name, type: WalletType.monero);
|
||||
final cacheFile = File(path);
|
||||
|
||||
if (cacheFile.existsSync()) {
|
||||
cacheFile.deleteSync();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool walletFilesExist(String path) =>
|
||||
!File(path).existsSync() && !File('$path.keys').existsSync();
|
||||
|
||||
|
@ -117,10 +109,10 @@ class MoneroWalletService extends WalletService<
|
|||
(info) => info.id == WalletBase.idFor(name, getType()),
|
||||
orElse: () => null);
|
||||
final wallet = MoneroWallet(walletInfo: walletInfo);
|
||||
final isValid = wallet.validate();
|
||||
final isValid = wallet.walletAddresses.validate();
|
||||
|
||||
if (!isValid) {
|
||||
await _removeCache(name);
|
||||
await restoreOrResetWalletFiles(name);
|
||||
wallet.close();
|
||||
return openWallet(name, password);
|
||||
}
|
||||
|
@ -135,7 +127,7 @@ class MoneroWalletService extends WalletService<
|
|||
(e is WalletOpeningException &&
|
||||
(e.message == 'std::bad_alloc' ||
|
||||
e.message.contains('bad_alloc')))) {
|
||||
await _removeCache(name);
|
||||
await restoreOrResetWalletFiles(name);
|
||||
return openWallet(name, password);
|
||||
}
|
||||
|
||||
|
|
88
lib/monero/monero_wallet_utils.dart
Normal file
88
lib/monero/monero_wallet_utils.dart
Normal file
|
@ -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);
|
||||
}
|
|
@ -37,7 +37,7 @@ void startCurrentWalletChangeReaction(AppStore appStore,
|
|||
await wallet.connectToNode(node: node);
|
||||
|
||||
if (wallet.walletInfo.address?.isEmpty ?? true) {
|
||||
wallet.walletInfo.address = wallet.address;
|
||||
wallet.walletInfo.address = wallet.walletAddresses.address;
|
||||
|
||||
if (wallet.walletInfo.isInBox) {
|
||||
await wallet.walletInfo.save();
|
||||
|
|
|
@ -151,17 +151,19 @@ class ContactListPage extends BasePage {
|
|||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
image ?? Offstage(),
|
||||
Padding(
|
||||
padding: image != null
|
||||
? EdgeInsets.only(left: 12)
|
||||
: EdgeInsets.only(left: 0),
|
||||
child: Text(
|
||||
contact.name,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: image != null
|
||||
? EdgeInsets.only(left: 12)
|
||||
: EdgeInsets.only(left: 0),
|
||||
child: Text(
|
||||
contact.name,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import 'dart:ui';
|
||||
import 'package:cake_wallet/entities/parsed_address.dart';
|
||||
import 'package:cake_wallet/entities/sync_status.dart';
|
||||
import 'package:cake_wallet/entities/wallet_type.dart';
|
||||
import 'package:cake_wallet/exchange/changenow/changenow_exchange_provider.dart';
|
||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||
import 'package:cake_wallet/src/screens/send/widgets/parse_address_from_domain_alert.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
|
||||
import 'package:dotted_border/dotted_border.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
@ -9,8 +11,6 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_template.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/limits_state.dart';
|
||||
|
@ -23,7 +23,6 @@ import 'package:cake_wallet/utils/show_pop_up.dart';
|
|||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/entities/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/xmrto/xmrto_exchange_provider.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/exchange_card.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
|
@ -42,7 +41,9 @@ class ExchangePage extends BasePage {
|
|||
final checkBoxKey = GlobalKey<StandardCheckboxState>();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final _depositAmountFocus = FocusNode();
|
||||
final _depositAddressFocus = FocusNode();
|
||||
final _receiveAmountFocus = FocusNode();
|
||||
final _receiveAddressFocus = FocusNode();
|
||||
var _isReactionsSet = false;
|
||||
|
||||
@override
|
||||
|
@ -171,6 +172,7 @@ class ExchangePage extends BasePage {
|
|||
.calculateDepositAllAmount()
|
||||
: null,
|
||||
amountFocusNode: _depositAmountFocus,
|
||||
addressFocusNode: _depositAddressFocus,
|
||||
key: depositKey,
|
||||
title: S.of(context).you_will_send,
|
||||
initialCurrency:
|
||||
|
@ -179,7 +181,7 @@ class ExchangePage extends BasePage {
|
|||
initialAddress:
|
||||
exchangeViewModel.depositCurrency ==
|
||||
exchangeViewModel.wallet.currency
|
||||
? exchangeViewModel.wallet.address
|
||||
? exchangeViewModel.wallet.walletAddresses.address
|
||||
: exchangeViewModel.depositAddress,
|
||||
initialIsAmountEditable: true,
|
||||
initialIsAddressEditable:
|
||||
|
@ -223,6 +225,15 @@ class ExchangePage extends BasePage {
|
|||
type: exchangeViewModel.wallet.type),
|
||||
addressTextFieldValidator: AddressValidator(
|
||||
type: exchangeViewModel.depositCurrency),
|
||||
onPushPasteButton: (context) async {
|
||||
final domain =
|
||||
exchangeViewModel.depositAddress;
|
||||
final ticker = exchangeViewModel
|
||||
.depositCurrency.title.toLowerCase();
|
||||
exchangeViewModel.depositAddress =
|
||||
await applyOpenaliasOrUnstoppableDomains(
|
||||
context, domain, ticker);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -232,6 +243,7 @@ class ExchangePage extends BasePage {
|
|||
child: Observer(
|
||||
builder: (_) => ExchangeCard(
|
||||
amountFocusNode: _receiveAmountFocus,
|
||||
addressFocusNode: _receiveAddressFocus,
|
||||
key: receiveKey,
|
||||
title: S.of(context).you_will_get,
|
||||
initialCurrency:
|
||||
|
@ -240,7 +252,7 @@ class ExchangePage extends BasePage {
|
|||
initialAddress: exchangeViewModel
|
||||
.receiveCurrency ==
|
||||
exchangeViewModel.wallet.currency
|
||||
? exchangeViewModel.wallet.address
|
||||
? exchangeViewModel.wallet.walletAddresses.address
|
||||
: exchangeViewModel.receiveAddress,
|
||||
initialIsAmountEditable: exchangeViewModel
|
||||
.isReceiveAmountEditable,
|
||||
|
@ -268,6 +280,15 @@ class ExchangePage extends BasePage {
|
|||
AddressValidator(
|
||||
type: exchangeViewModel
|
||||
.receiveCurrency),
|
||||
onPushPasteButton: (context) async {
|
||||
final domain =
|
||||
exchangeViewModel.receiveAddress;
|
||||
final ticker = exchangeViewModel
|
||||
.receiveCurrency.title.toLowerCase();
|
||||
exchangeViewModel.receiveAddress =
|
||||
await applyOpenaliasOrUnstoppableDomains(
|
||||
context, domain, ticker);
|
||||
},
|
||||
)),
|
||||
)
|
||||
],
|
||||
|
@ -371,7 +392,7 @@ class ExchangePage extends BasePage {
|
|||
from: template.depositCurrency,
|
||||
to: template.receiveCurrency,
|
||||
onTap: () {
|
||||
applyTemplate(
|
||||
applyTemplate(context,
|
||||
exchangeViewModel, template);
|
||||
},
|
||||
onRemove: () {
|
||||
|
@ -472,8 +493,8 @@ class ExchangePage extends BasePage {
|
|||
));
|
||||
}
|
||||
|
||||
void applyTemplate(
|
||||
ExchangeViewModel exchangeViewModel, ExchangeTemplate template) {
|
||||
void applyTemplate(BuildContext context,
|
||||
ExchangeViewModel exchangeViewModel, ExchangeTemplate template) async {
|
||||
exchangeViewModel.changeDepositCurrency(
|
||||
currency: CryptoCurrency.fromString(template.depositCurrency));
|
||||
exchangeViewModel.changeReceiveCurrency(
|
||||
|
@ -491,6 +512,16 @@ class ExchangePage extends BasePage {
|
|||
exchangeViewModel.receiveAddress = template.receiveAddress;
|
||||
exchangeViewModel.isReceiveAmountEntered = false;
|
||||
exchangeViewModel.isFixedRateMode = false;
|
||||
|
||||
var domain = template.depositAddress;
|
||||
var ticker = template.depositCurrency.toLowerCase();
|
||||
exchangeViewModel.depositAddress =
|
||||
await applyOpenaliasOrUnstoppableDomains(context, domain, ticker);
|
||||
|
||||
domain = template.receiveAddress;
|
||||
ticker = template.receiveCurrency.toLowerCase();
|
||||
exchangeViewModel.receiveAddress =
|
||||
await applyOpenaliasOrUnstoppableDomains(context, domain, ticker);
|
||||
}
|
||||
|
||||
void _setReactions(
|
||||
|
@ -646,7 +677,8 @@ class ExchangePage extends BasePage {
|
|||
}
|
||||
});
|
||||
|
||||
reaction((_) => exchangeViewModel.wallet.address, (String address) {
|
||||
reaction((_) => exchangeViewModel.wallet.walletAddresses.address,
|
||||
(String address) {
|
||||
if (exchangeViewModel.depositCurrency == CryptoCurrency.xmr) {
|
||||
depositKey.currentState.changeAddress(address: address);
|
||||
}
|
||||
|
@ -656,6 +688,26 @@ class ExchangePage extends BasePage {
|
|||
}
|
||||
});
|
||||
|
||||
_depositAddressFocus.addListener(() async {
|
||||
if (!_depositAddressFocus.hasFocus &&
|
||||
depositAddressController.text.isNotEmpty) {
|
||||
final domain = depositAddressController.text;
|
||||
final ticker = exchangeViewModel.depositCurrency.title.toLowerCase();
|
||||
exchangeViewModel.depositAddress =
|
||||
await applyOpenaliasOrUnstoppableDomains(context, domain, ticker);
|
||||
}
|
||||
});
|
||||
|
||||
_receiveAddressFocus.addListener(() async {
|
||||
if (!_receiveAddressFocus.hasFocus &&
|
||||
receiveAddressController.text.isNotEmpty) {
|
||||
final domain = receiveAddressController.text;
|
||||
final ticker = exchangeViewModel.receiveCurrency.title.toLowerCase();
|
||||
exchangeViewModel.receiveAddress =
|
||||
await applyOpenaliasOrUnstoppableDomains(context, domain, ticker);
|
||||
}
|
||||
});
|
||||
|
||||
_receiveAmountFocus.addListener(() {
|
||||
if (_receiveAmountFocus.hasFocus && !exchangeViewModel.isFixedRateMode) {
|
||||
showPopUp<void>(
|
||||
|
@ -707,7 +759,8 @@ class ExchangePage extends BasePage {
|
|||
isCurrentTypeWallet ? exchangeViewModel.wallet.name : null);
|
||||
|
||||
key.currentState.changeAddress(
|
||||
address: isCurrentTypeWallet ? exchangeViewModel.wallet.address : '');
|
||||
address: isCurrentTypeWallet
|
||||
? exchangeViewModel.wallet.walletAddresses.address : '');
|
||||
|
||||
key.currentState.changeAmount(amount: '');
|
||||
}
|
||||
|
@ -719,11 +772,35 @@ class ExchangePage extends BasePage {
|
|||
if (isCurrentTypeWallet) {
|
||||
key.currentState.changeWalletName(exchangeViewModel.wallet.name);
|
||||
key.currentState.addressController.text =
|
||||
exchangeViewModel.wallet.address;
|
||||
exchangeViewModel.wallet.walletAddresses.address;
|
||||
} else if (key.currentState.addressController.text ==
|
||||
exchangeViewModel.wallet.address) {
|
||||
exchangeViewModel.wallet.walletAddresses.address) {
|
||||
key.currentState.changeWalletName(null);
|
||||
key.currentState.addressController.text = null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> applyOpenaliasOrUnstoppableDomains(
|
||||
BuildContext context, String domain, String ticker) async {
|
||||
final parsedAddress = await parseAddressFromDomain(domain, ticker);
|
||||
|
||||
switch (parsedAddress.parseFrom) {
|
||||
case ParseFrom.unstoppableDomains:
|
||||
showAddressAlert(
|
||||
context,
|
||||
S.of(context).address_detected,
|
||||
S.of(context).address_from_domain(parsedAddress.name));
|
||||
break;
|
||||
case ParseFrom.openAlias:
|
||||
showAddressAlert(
|
||||
context,
|
||||
S.of(context).openalias_alert_title,
|
||||
S.of(context).openalias_alert_content(parsedAddress.name));
|
||||
break;
|
||||
case ParseFrom.notParsed:
|
||||
break;
|
||||
}
|
||||
|
||||
return parsedAddress.address;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ class ExchangeTemplatePage extends BasePage {
|
|||
initialAddress: exchangeViewModel
|
||||
.depositCurrency ==
|
||||
exchangeViewModel.wallet.currency
|
||||
? exchangeViewModel.wallet.address
|
||||
? exchangeViewModel.wallet.walletAddresses.address
|
||||
: exchangeViewModel.depositAddress,
|
||||
initialIsAmountEditable: true,
|
||||
initialIsAddressEditable: exchangeViewModel
|
||||
|
@ -150,9 +150,8 @@ class ExchangeTemplatePage extends BasePage {
|
|||
.color,
|
||||
currencyValueValidator: AmountValidator(
|
||||
type: exchangeViewModel.wallet.type),
|
||||
addressTextFieldValidator: AddressValidator(
|
||||
type:
|
||||
exchangeViewModel.depositCurrency),
|
||||
//addressTextFieldValidator: AddressValidator(
|
||||
// type: exchangeViewModel.depositCurrency),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -168,7 +167,7 @@ class ExchangeTemplatePage extends BasePage {
|
|||
initialAddress:
|
||||
exchangeViewModel.receiveCurrency ==
|
||||
exchangeViewModel.wallet.currency
|
||||
? exchangeViewModel.wallet.address
|
||||
? exchangeViewModel.wallet.walletAddresses.address
|
||||
: exchangeViewModel.receiveAddress,
|
||||
initialIsAmountEditable:
|
||||
exchangeViewModel.provider is
|
||||
|
@ -190,8 +189,8 @@ class ExchangeTemplatePage extends BasePage {
|
|||
.decorationColor,
|
||||
currencyValueValidator: AmountValidator(
|
||||
type: exchangeViewModel.wallet.type),
|
||||
addressTextFieldValidator: AddressValidator(
|
||||
type: exchangeViewModel.receiveCurrency),
|
||||
//addressTextFieldValidator: AddressValidator(
|
||||
// type: exchangeViewModel.receiveCurrency),
|
||||
)),
|
||||
)
|
||||
],
|
||||
|
@ -383,7 +382,8 @@ class ExchangeTemplatePage extends BasePage {
|
|||
}
|
||||
});
|
||||
|
||||
reaction((_) => exchangeViewModel.wallet.address, (String address) {
|
||||
reaction((_) => exchangeViewModel.wallet.walletAddresses.address,
|
||||
(String address) {
|
||||
if (exchangeViewModel.depositCurrency == CryptoCurrency.xmr) {
|
||||
depositKey.currentState.changeAddress(address: address);
|
||||
}
|
||||
|
@ -405,7 +405,8 @@ class ExchangeTemplatePage extends BasePage {
|
|||
isCurrentTypeWallet ? exchangeViewModel.wallet.name : null);
|
||||
|
||||
key.currentState.changeAddress(
|
||||
address: isCurrentTypeWallet ? exchangeViewModel.wallet.address : '');
|
||||
address: isCurrentTypeWallet
|
||||
? exchangeViewModel.wallet.walletAddresses.address : '');
|
||||
|
||||
key.currentState.changeAmount(amount: '');
|
||||
}
|
||||
|
@ -417,9 +418,9 @@ class ExchangeTemplatePage extends BasePage {
|
|||
if (isCurrentTypeWallet) {
|
||||
key.currentState.changeWalletName(exchangeViewModel.wallet.name);
|
||||
key.currentState.addressController.text =
|
||||
exchangeViewModel.wallet.address;
|
||||
exchangeViewModel.wallet.walletAddresses.address;
|
||||
} else if (key.currentState.addressController.text ==
|
||||
exchangeViewModel.wallet.address) {
|
||||
exchangeViewModel.wallet.walletAddresses.address) {
|
||||
key.currentState.changeWalletName(null);
|
||||
key.currentState.addressController.text = null;
|
||||
}
|
||||
|
|
|
@ -28,8 +28,10 @@ class ExchangeCard extends StatefulWidget {
|
|||
this.currencyValueValidator,
|
||||
this.addressTextFieldValidator,
|
||||
this.amountFocusNode,
|
||||
this.addressFocusNode,
|
||||
this.hasAllAmount = false,
|
||||
this.allAmount})
|
||||
this.allAmount,
|
||||
this.onPushPasteButton})
|
||||
: super(key: key);
|
||||
|
||||
final List<CryptoCurrency> currencies;
|
||||
|
@ -49,8 +51,10 @@ class ExchangeCard extends StatefulWidget {
|
|||
final FormFieldValidator<String> currencyValueValidator;
|
||||
final FormFieldValidator<String> addressTextFieldValidator;
|
||||
final FocusNode amountFocusNode;
|
||||
final FocusNode addressFocusNode;
|
||||
final bool hasAllAmount;
|
||||
Function allAmount;
|
||||
final Function allAmount;
|
||||
final Function(BuildContext context) onPushPasteButton;
|
||||
|
||||
@override
|
||||
ExchangeCardState createState() => ExchangeCardState();
|
||||
|
@ -288,6 +292,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
? Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: AddressTextField(
|
||||
focusNode: widget.addressFocusNode,
|
||||
controller: addressController,
|
||||
placeholder: widget.hasRefundAddress
|
||||
? S.of(context).refund_address
|
||||
|
@ -311,6 +316,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
.decorationColor),
|
||||
buttonColor: widget.addressButtonsColor,
|
||||
validator: widget.addressTextFieldValidator,
|
||||
onPushPasteButton: widget.onPushPasteButton,
|
||||
),
|
||||
)
|
||||
: Padding(
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import 'dart:ui';
|
||||
import 'package:cake_wallet/entities/monero_transaction_priority.dart';
|
||||
import 'package:cake_wallet/entities/parsed_address.dart';
|
||||
import 'package:cake_wallet/entities/transaction_priority.dart';
|
||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||
import 'package:cake_wallet/src/screens/send/widgets/parse_address_from_domain_alert.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
|
@ -40,7 +42,7 @@ class SendPage extends BasePage {
|
|||
_addressFocusNode = FocusNode() {
|
||||
_addressFocusNode.addListener(() {
|
||||
if (!_addressFocusNode.hasFocus && _addressController.text.isNotEmpty) {
|
||||
getOpenaliasRecord(_addressFocusNode.context);
|
||||
applyOpenaliasOrUnstoppableDomains(_addressFocusNode.context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -173,6 +175,9 @@ class SendPage extends BasePage {
|
|||
.headline
|
||||
.decorationColor),
|
||||
validator: sendViewModel.addressValidator,
|
||||
onPushPasteButton: (context) {
|
||||
applyOpenaliasOrUnstoppableDomains(context);
|
||||
},
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => Padding(
|
||||
|
@ -542,7 +547,7 @@ class SendPage extends BasePage {
|
|||
template.address;
|
||||
_cryptoAmountController.text =
|
||||
template.amount;
|
||||
getOpenaliasRecord(context);
|
||||
applyOpenaliasOrUnstoppableDomains(context);
|
||||
},
|
||||
onRemove: () {
|
||||
showPopUp<void>(
|
||||
|
@ -757,26 +762,6 @@ class SendPage extends BasePage {
|
|||
_effectsInstalled = true;
|
||||
}
|
||||
|
||||
Future<void> getOpenaliasRecord(BuildContext context) async {
|
||||
final record =
|
||||
await sendViewModel.decodeOpenaliasRecord(_addressController.text);
|
||||
|
||||
if (record != null) {
|
||||
_addressController.text = record.address;
|
||||
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).openalias_alert_title,
|
||||
alertContent:
|
||||
S.of(context).openalias_alert_content(record.name),
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _setTransactionPriority(BuildContext context) async {
|
||||
final items = priorityForWalletType(sendViewModel.walletType);
|
||||
final selectedItem = items.indexOf(sendViewModel.transactionPriority);
|
||||
|
@ -794,4 +779,28 @@ class SendPage extends BasePage {
|
|||
),
|
||||
context: context);
|
||||
}
|
||||
|
||||
void applyOpenaliasOrUnstoppableDomains(BuildContext context) async {
|
||||
final domain = _addressController.text;
|
||||
final ticker = sendViewModel.currency.title.toLowerCase();
|
||||
final parsedAddress = await parseAddressFromDomain(domain, ticker);
|
||||
_addressController.text = parsedAddress.address;
|
||||
|
||||
switch (parsedAddress.parseFrom) {
|
||||
case ParseFrom.unstoppableDomains:
|
||||
showAddressAlert(
|
||||
context,
|
||||
S.of(context).address_detected,
|
||||
S.of(context).address_from_domain(parsedAddress.name));
|
||||
break;
|
||||
case ParseFrom.openAlias:
|
||||
showAddressAlert(
|
||||
context,
|
||||
S.of(context).openalias_alert_title,
|
||||
S.of(context).openalias_alert_content(parsedAddress.name));
|
||||
break;
|
||||
case ParseFrom.notParsed:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ class SendTemplatePage extends BasePage {
|
|||
.primaryTextTheme
|
||||
.headline
|
||||
.decorationColor),
|
||||
validator: sendViewModel.addressValidator,
|
||||
//validator: sendViewModel.addressValidator,
|
||||
),
|
||||
),
|
||||
Observer(builder: (_) {
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
|
@ -24,7 +24,8 @@ class AddressTextField extends StatelessWidget {
|
|||
this.iconColor,
|
||||
this.textStyle,
|
||||
this.hintStyle,
|
||||
this.validator});
|
||||
this.validator,
|
||||
this.onPushPasteButton});
|
||||
|
||||
static const prefixIconWidth = 34.0;
|
||||
static const prefixIconHeight = 34.0;
|
||||
|
@ -43,6 +44,7 @@ class AddressTextField extends StatelessWidget {
|
|||
final TextStyle textStyle;
|
||||
final TextStyle hintStyle;
|
||||
final FocusNode focusNode;
|
||||
final Function(BuildContext context) onPushPasteButton;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -225,5 +227,7 @@ class AddressTextField extends StatelessWidget {
|
|||
if (address?.isNotEmpty ?? false) {
|
||||
controller.text = address;
|
||||
}
|
||||
|
||||
onPushPasteButton?.call(context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,11 +16,22 @@ class ContactListViewModel = ContactListViewModelBase
|
|||
abstract class ContactListViewModelBase with Store {
|
||||
ContactListViewModelBase(this.contactSource, this.walletInfoSource)
|
||||
: contacts = ObservableList<ContactRecord>(),
|
||||
walletContacts = walletInfoSource.values
|
||||
.where((info) => info.address?.isNotEmpty ?? false)
|
||||
.map((info) => WalletContact(
|
||||
info.address, info.name, walletTypeToCryptoCurrency(info.type)))
|
||||
.toList() {
|
||||
walletContacts = [] {
|
||||
walletInfoSource.values.forEach((info) {
|
||||
if (info.addresses?.isNotEmpty ?? false) {
|
||||
info.addresses?.forEach((address, label) {
|
||||
final name = label.isNotEmpty
|
||||
? info.name + ' ($label)'
|
||||
: info.name;
|
||||
|
||||
walletContacts.add(WalletContact(
|
||||
address,
|
||||
name,
|
||||
walletTypeToCryptoCurrency(info.type)));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
_subscription = contactSource.bindToListWithTransform(
|
||||
contacts, (Contact contact) => ContactRecord(contactSource, contact),
|
||||
initialFire: true);
|
||||
|
|
|
@ -92,17 +92,17 @@ abstract class DashboardViewModelBase with Store {
|
|||
final _wallet = wallet;
|
||||
|
||||
if (_wallet is MoneroWallet) {
|
||||
subname = _wallet.account?.label;
|
||||
subname = _wallet.walletAddresses.account?.label;
|
||||
|
||||
_onMoneroAccountChangeReaction = reaction((_) => _wallet.account,
|
||||
(Account account) => _onMoneroAccountChange(_wallet));
|
||||
_onMoneroAccountChangeReaction = reaction((_) => _wallet.walletAddresses
|
||||
.account, (Account account) => _onMoneroAccountChange(_wallet));
|
||||
|
||||
_onMoneroBalanceChangeReaction = reaction((_) => _wallet.balance,
|
||||
(MoneroBalance balance) => _onMoneroTransactionsUpdate(_wallet));
|
||||
|
||||
final _accountTransactions = _wallet
|
||||
.transactionHistory.transactions.values
|
||||
.where((tx) => tx.accountIndex == _wallet.account.id)
|
||||
.where((tx) => tx.accountIndex == _wallet.walletAddresses.account.id)
|
||||
.toList();
|
||||
|
||||
transactions = ObservableList.of(_accountTransactions.map((transaction) =>
|
||||
|
@ -131,7 +131,7 @@ abstract class DashboardViewModelBase with Store {
|
|||
filter: (TransactionInfo tx) {
|
||||
final wallet = _wallet;
|
||||
if (tx is MoneroTransactionInfo && wallet is MoneroWallet) {
|
||||
return tx.accountIndex == wallet.account.id;
|
||||
return tx.accountIndex == wallet.walletAddresses.account.id;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -153,7 +153,7 @@ abstract class DashboardViewModelBase with Store {
|
|||
String subname;
|
||||
|
||||
@computed
|
||||
String get address => wallet.address;
|
||||
String get address => wallet.walletAddresses.address;
|
||||
|
||||
@computed
|
||||
SyncStatus get status => wallet.syncStatus;
|
||||
|
@ -251,13 +251,13 @@ abstract class DashboardViewModelBase with Store {
|
|||
wallet.type == WalletType.bitcoin && wallet.seed.split(' ').length < 24;
|
||||
|
||||
if (wallet is MoneroWallet) {
|
||||
subname = wallet.account?.label;
|
||||
subname = wallet.walletAddresses.account?.label;
|
||||
|
||||
_onMoneroAccountChangeReaction?.reaction?.dispose();
|
||||
_onMoneroBalanceChangeReaction?.reaction?.dispose();
|
||||
|
||||
_onMoneroAccountChangeReaction = reaction((_) => wallet.account,
|
||||
(Account account) => _onMoneroAccountChange(wallet));
|
||||
_onMoneroAccountChangeReaction = reaction((_) => wallet.walletAddresses
|
||||
.account, (Account account) => _onMoneroAccountChange(wallet));
|
||||
|
||||
_onMoneroBalanceChangeReaction = reaction((_) => wallet.balance,
|
||||
(MoneroBalance balance) => _onMoneroTransactionsUpdate(wallet));
|
||||
|
@ -284,7 +284,7 @@ abstract class DashboardViewModelBase with Store {
|
|||
settingsStore: appStore.settingsStore),
|
||||
filter: (TransactionInfo tx) {
|
||||
if (tx is MoneroTransactionInfo && wallet is MoneroWallet) {
|
||||
return tx.accountIndex == wallet.account.id;
|
||||
return tx.accountIndex == wallet.walletAddresses.account.id;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -293,7 +293,7 @@ abstract class DashboardViewModelBase with Store {
|
|||
|
||||
@action
|
||||
void _onMoneroAccountChange(MoneroWallet wallet) {
|
||||
subname = wallet.account?.label;
|
||||
subname = wallet.walletAddresses.account?.label;
|
||||
_onMoneroTransactionsUpdate(wallet);
|
||||
}
|
||||
|
||||
|
@ -302,7 +302,7 @@ abstract class DashboardViewModelBase with Store {
|
|||
transactions.clear();
|
||||
|
||||
final _accountTransactions = wallet.transactionHistory.transactions.values
|
||||
.where((tx) => tx.accountIndex == wallet.account.id)
|
||||
.where((tx) => tx.accountIndex == wallet.walletAddresses.account.id)
|
||||
.toList();
|
||||
|
||||
transactions.addAll(_accountTransactions.map((transaction) =>
|
||||
|
|
|
@ -41,7 +41,8 @@ abstract class ExchangeViewModelBase with Store {
|
|||
depositAmount = '';
|
||||
receiveAmount = '';
|
||||
receiveAddress = '';
|
||||
depositAddress = depositCurrency == wallet.currency ? wallet.address : '';
|
||||
depositAddress = depositCurrency == wallet.currency
|
||||
? wallet.walletAddresses.address : '';
|
||||
limitsState = LimitsInitialState();
|
||||
tradeState = ExchangeTradeStateInitial();
|
||||
_cryptoNumberFormat = NumberFormat()..maximumFractionDigits = 12;
|
||||
|
@ -308,8 +309,10 @@ abstract class ExchangeViewModelBase with Store {
|
|||
isReceiveAmountEntered = false;
|
||||
depositAmount = '';
|
||||
receiveAmount = '';
|
||||
depositAddress = depositCurrency == wallet.currency ? wallet.address : '';
|
||||
receiveAddress = receiveCurrency == wallet.currency ? wallet.address : '';
|
||||
depositAddress = depositCurrency == wallet.currency
|
||||
? wallet.walletAddresses.address : '';
|
||||
receiveAddress = receiveCurrency == wallet.currency
|
||||
? wallet.walletAddresses.address : '';
|
||||
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
||||
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
|
||||
isFixedRateMode = false;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:cake_wallet/core/wallet_base.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/monero/monero_account_list.dart';
|
||||
|
@ -10,11 +12,12 @@ class MoneroAccountEditOrCreateViewModel = MoneroAccountEditOrCreateViewModelBas
|
|||
|
||||
abstract class MoneroAccountEditOrCreateViewModelBase with Store {
|
||||
MoneroAccountEditOrCreateViewModelBase(this._moneroAccountList,
|
||||
{AccountListItem accountListItem})
|
||||
{@required WalletBase wallet, AccountListItem accountListItem})
|
||||
: state = InitialExecutionState(),
|
||||
isEdit = accountListItem != null,
|
||||
label = accountListItem?.label??'',
|
||||
_accountListItem = accountListItem;
|
||||
_accountListItem = accountListItem,
|
||||
_wallet = wallet;
|
||||
|
||||
final bool isEdit;
|
||||
|
||||
|
@ -26,6 +29,7 @@ abstract class MoneroAccountEditOrCreateViewModelBase with Store {
|
|||
|
||||
final MoneroAccountList _moneroAccountList;
|
||||
final AccountListItem _accountListItem;
|
||||
final WalletBase _wallet;
|
||||
|
||||
Future<void> save() async {
|
||||
try {
|
||||
|
@ -38,6 +42,7 @@ abstract class MoneroAccountEditOrCreateViewModelBase with Store {
|
|||
await _moneroAccountList.addAccount(label: label);
|
||||
}
|
||||
|
||||
await _wallet.save();
|
||||
state = ExecutedSuccessfullyState();
|
||||
} catch (e) {
|
||||
state = FailureState(e.toString());
|
||||
|
|
|
@ -20,15 +20,16 @@ abstract class MoneroAccountListViewModelBase with Store {
|
|||
}
|
||||
|
||||
@computed
|
||||
List<AccountListItem> get accounts => _moneroWallet.accountList.accounts
|
||||
.map((acc) => AccountListItem(
|
||||
List<AccountListItem> get accounts => _moneroWallet.walletAddresses
|
||||
.accountList.accounts.map((acc) => AccountListItem(
|
||||
label: acc.label,
|
||||
id: acc.id,
|
||||
isSelected: acc.id == _moneroWallet.account.id))
|
||||
isSelected: acc.id == _moneroWallet.walletAddresses.account.id))
|
||||
.toList();
|
||||
|
||||
final MoneroWallet _moneroWallet;
|
||||
|
||||
void select(AccountListItem item) =>
|
||||
_moneroWallet.account = Account(id: item.id, label: item.label);
|
||||
_moneroWallet.walletAddresses.account =
|
||||
Account(id: item.id, label: item.label);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
|
|||
import 'package:hive/hive.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/entities/openalias_record.dart';
|
||||
import 'package:cake_wallet/entities/template.dart';
|
||||
import 'package:cake_wallet/store/templates/send_template_store.dart';
|
||||
import 'package:cake_wallet/core/template_validator.dart';
|
||||
|
@ -267,13 +266,6 @@ abstract class SendViewModelBase with Store {
|
|||
void setTransactionPriority(TransactionPriority priority) =>
|
||||
_settingsStore.priority[_wallet.type] = priority;
|
||||
|
||||
Future<OpenaliasRecord> decodeOpenaliasRecord(String name) async {
|
||||
final record = await OpenaliasRecord.fetchAddressAndName(
|
||||
OpenaliasRecord.formatDomainName(name));
|
||||
|
||||
return record.name != name ? record : null;
|
||||
}
|
||||
|
||||
@action
|
||||
void _updateFiatAmount() {
|
||||
try {
|
||||
|
|
|
@ -64,12 +64,15 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
|
|||
final wallet = _wallet;
|
||||
|
||||
if (wallet is ElectrumWallet) {
|
||||
await wallet.generateNewAddress();
|
||||
await wallet.walletAddresses.generateNewAddress();
|
||||
await wallet.save();
|
||||
}
|
||||
|
||||
if (wallet is MoneroWallet) {
|
||||
await wallet.subaddressList
|
||||
.addSubaddress(accountIndex: wallet.account.id, label: label);
|
||||
await wallet.walletAddresses.subaddressList
|
||||
.addSubaddress(
|
||||
accountIndex: wallet.walletAddresses.account.id,
|
||||
label: label);
|
||||
await wallet.save();
|
||||
}
|
||||
}
|
||||
|
@ -77,13 +80,14 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
|
|||
Future<void> _update() async {
|
||||
final wallet = _wallet;
|
||||
|
||||
if (wallet is BitcoinWallet) {
|
||||
await wallet.updateAddress(_item.address as String);
|
||||
}
|
||||
/*if (wallet is BitcoinWallet) {
|
||||
await wallet.walletAddresses.updateAddress(_item.address as String);
|
||||
await wallet.save();
|
||||
}*/
|
||||
|
||||
if (wallet is MoneroWallet) {
|
||||
await wallet.subaddressList.setLabelSubaddress(
|
||||
accountIndex: wallet.account.id,
|
||||
await wallet.walletAddresses.subaddressList.setLabelSubaddress(
|
||||
accountIndex: wallet.walletAddresses.account.id,
|
||||
addressIndex: _item.id as int,
|
||||
label: label);
|
||||
await wallet.save();
|
||||
|
|
|
@ -80,7 +80,7 @@ abstract class WalletAddressListViewModelBase with Store {
|
|||
|
||||
@computed
|
||||
WalletAddressListItem get address =>
|
||||
WalletAddressListItem(address: _wallet.address);
|
||||
WalletAddressListItem(address: _wallet.walletAddresses.address);
|
||||
|
||||
@computed
|
||||
PaymentURI get uri {
|
||||
|
@ -105,8 +105,10 @@ abstract class WalletAddressListViewModelBase with Store {
|
|||
final addressList = ObservableList<ListItem>();
|
||||
|
||||
if (wallet is MoneroWallet) {
|
||||
final primaryAddress = wallet.subaddressList.subaddresses.first;
|
||||
addressList.addAll(wallet.subaddressList.subaddresses.map((subaddress) {
|
||||
final primaryAddress =
|
||||
wallet.walletAddresses.subaddressList.subaddresses.first;
|
||||
addressList.addAll(wallet.walletAddresses.subaddressList.subaddresses
|
||||
.map((subaddress) {
|
||||
final isPrimary = subaddress == primaryAddress;
|
||||
|
||||
return WalletAddressListItem(
|
||||
|
@ -118,8 +120,8 @@ abstract class WalletAddressListViewModelBase with Store {
|
|||
}
|
||||
|
||||
if (wallet is BitcoinWallet) {
|
||||
final primaryAddress = wallet.addresses.first;
|
||||
final bitcoinAddresses = wallet.addresses.map((addr) {
|
||||
final primaryAddress = wallet.walletAddresses.addresses.first;
|
||||
final bitcoinAddresses = wallet.walletAddresses.addresses.map((addr) {
|
||||
final isPrimary = addr == primaryAddress;
|
||||
|
||||
return WalletAddressListItem(
|
||||
|
@ -139,7 +141,7 @@ abstract class WalletAddressListViewModelBase with Store {
|
|||
final wallet = _wallet;
|
||||
|
||||
if (wallet is MoneroWallet) {
|
||||
return wallet.account.label;
|
||||
return wallet.walletAddresses.account.label;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -160,7 +162,7 @@ abstract class WalletAddressListViewModelBase with Store {
|
|||
|
||||
@action
|
||||
void setAddress(WalletAddressListItem address) =>
|
||||
_wallet.address = address.address;
|
||||
_wallet.walletAddresses.address = address.address;
|
||||
|
||||
void _init() {
|
||||
_baseItems = [];
|
||||
|
@ -177,7 +179,8 @@ abstract class WalletAddressListViewModelBase with Store {
|
|||
final wallet = _wallet;
|
||||
|
||||
if (wallet is ElectrumWallet) {
|
||||
wallet.nextAddress();
|
||||
wallet.walletAddresses.nextAddress();
|
||||
wallet.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ abstract class WalletCreationVMBase with Store {
|
|||
dirPath: dirPath);
|
||||
credentials.walletInfo = walletInfo;
|
||||
final wallet = await process(credentials);
|
||||
walletInfo.address = wallet.address;
|
||||
walletInfo.address = wallet.walletAddresses.address;
|
||||
await _walletInfoSource.add(walletInfo);
|
||||
_appStore.changeCurrentWallet(wallet);
|
||||
_appStore.authenticationStore.allowed();
|
||||
|
|
|
@ -481,12 +481,15 @@
|
|||
"buy_bitcoin" : "Bitcoin kaufen",
|
||||
"buy_with" : "Kaufen mit",
|
||||
"moonpay_alert_text" : "Der Wert des Betrags muss größer oder gleich ${minAmount} ${fiatCurrency} sein",
|
||||
|
||||
|
||||
"outdated_electrum_wallet_receive_warning": "Wenn diese Brieftasche einen 12-Wort-Seed hat und in Cake erstellt wurde, zahlen Sie KEINE Bitcoins in diese Brieftasche ein. Alle auf diese Wallet übertragenen BTC können verloren gehen. Erstellen Sie eine neue 24-Wort-Wallet (tippen Sie auf das Menü oben rechts, wählen Sie Wallets, wählen Sie Neue Wallet erstellen und dann Bitcoin) und verschieben Sie Ihre BTC SOFORT dorthin. Neue (24-Wort-)BTC-Wallets von Cake sind sicher",
|
||||
"do_not_show_me": "Zeig mir das nicht noch einmal",
|
||||
|
||||
"unspent_coins_title" : "Nicht ausgegebene Münzen",
|
||||
"unspent_coins_details_title" : "Details zu nicht ausgegebenen Münzen",
|
||||
"freeze" : "Einfrieren",
|
||||
"coin_control" : "Münzkontrolle (optional)"
|
||||
"coin_control" : "Münzkontrolle (optional)",
|
||||
|
||||
"address_detected" : "Adresse erkannt",
|
||||
"address_from_domain" : "Sie haben die Adresse von der unaufhaltsamen Domain ${domain} erhalten"
|
||||
}
|
||||
|
|
|
@ -488,5 +488,8 @@
|
|||
"unspent_coins_title" : "Unspent coins",
|
||||
"unspent_coins_details_title" : "Unspent coins details",
|
||||
"freeze" : "Freeze",
|
||||
"coin_control" : "Coin control (optional)"
|
||||
"coin_control" : "Coin control (optional)",
|
||||
|
||||
"address_detected" : "Address detected",
|
||||
"address_from_domain" : "You got address from unstoppable domain ${domain}"
|
||||
}
|
|
@ -472,7 +472,7 @@
|
|||
"submit_request" : "presentar una solicitud",
|
||||
|
||||
"buy_alert_content" : "Actualmente solo apoyamos la compra de Bitcoin y Litecoin. Para comprar Bitcoin o Litecoin, cree o cambie a su billetera Bitcoin o Litecoin.",
|
||||
|
||||
|
||||
"outdated_electrum_wallet_description" : "Las nuevas carteras de Bitcoin creadas en Cake ahora tienen una semilla de 24 palabras. Es obligatorio que cree una nueva billetera de Bitcoin y transfiera todos sus fondos a la nueva billetera de 24 palabras, y deje de usar billeteras con una semilla de 12 palabras. Haga esto de inmediato para asegurar sus fondos.",
|
||||
"understand" : "Entiendo",
|
||||
|
||||
|
@ -488,5 +488,8 @@
|
|||
"unspent_coins_title" : "Monedas no gastadas",
|
||||
"unspent_coins_details_title" : "Detalles de monedas no gastadas",
|
||||
"freeze" : "Congelar",
|
||||
"coin_control" : "Control de monedas (opcional)"
|
||||
"coin_control" : "Control de monedas (opcional)",
|
||||
|
||||
"address_detected" : "Dirección detectada",
|
||||
"address_from_domain" : "Tienes la dirección de unstoppable domain ${domain}"
|
||||
}
|
|
@ -488,5 +488,8 @@
|
|||
"unspent_coins_title" : "खर्च न किए गए सिक्के",
|
||||
"unspent_coins_details_title" : "अव्ययित सिक्कों का विवरण",
|
||||
"freeze" : "फ्रीज",
|
||||
"coin_control" : "सिक्का नियंत्रण (वैकल्पिक)"
|
||||
"coin_control" : "सिक्का नियंत्रण (वैकल्पिक)",
|
||||
|
||||
"address_detected" : "पता लग गया",
|
||||
"address_from_domain" : "आपको अजेय डोमेन ${domain} से पता मिला है"
|
||||
}
|
|
@ -488,5 +488,8 @@
|
|||
"unspent_coins_title" : "Nepotrošeni novčići",
|
||||
"unspent_coins_details_title" : "Nepotrošeni detalji o novčićima",
|
||||
"freeze" : "Zamrznuti",
|
||||
"coin_control" : "Kontrola novca (nije obavezno)"
|
||||
"coin_control" : "Kontrola novca (nije obavezno)",
|
||||
|
||||
"address_detected" : "Adresa je otkrivena",
|
||||
"address_from_domain" : "Dobili ste adresu od unstoppable domain ${domain}"
|
||||
}
|
|
@ -488,5 +488,8 @@
|
|||
"unspent_coins_title" : "Monete non spese",
|
||||
"unspent_coins_details_title" : "Dettagli sulle monete non spese",
|
||||
"freeze" : "Congelare",
|
||||
"coin_control" : "Controllo monete (opzionale)"
|
||||
"coin_control" : "Controllo monete (opzionale)",
|
||||
|
||||
"address_detected" : "Indirizzo rilevato",
|
||||
"address_from_domain" : "Hai l'indirizzo da unstoppable domain ${domain}"
|
||||
}
|
|
@ -488,5 +488,8 @@
|
|||
"unspent_coins_title" : "未使用のコイン",
|
||||
"unspent_coins_details_title" : "未使用のコインの詳細",
|
||||
"freeze" : "氷結",
|
||||
"coin_control" : "コインコントロール(オプション)"
|
||||
"coin_control" : "コインコントロール(オプション)",
|
||||
|
||||
"address_detected" : "アドレスが検出されました",
|
||||
"address_from_domain" : "あなたはからアドレスを得ました unstoppable domain ${domain}"
|
||||
}
|
|
@ -488,5 +488,8 @@
|
|||
"unspent_coins_title" : "사용하지 않은 동전",
|
||||
"unspent_coins_details_title" : "사용하지 않은 동전 세부 정보",
|
||||
"freeze" : "얼다",
|
||||
"coin_control" : "코인 제어 (옵션)"
|
||||
"coin_control" : "코인 제어 (옵션)",
|
||||
|
||||
"address_detected" : "주소 감지",
|
||||
"address_from_domain" : "주소는 unstoppable domain ${domain}"
|
||||
}
|
|
@ -488,5 +488,8 @@
|
|||
"unspent_coins_title" : "Ongebruikte munten",
|
||||
"unspent_coins_details_title" : "Details van niet-uitgegeven munten",
|
||||
"freeze" : "Bevriezen",
|
||||
"coin_control" : "Muntcontrole (optioneel)"
|
||||
"coin_control" : "Muntcontrole (optioneel)",
|
||||
|
||||
"address_detected" : "Adres gedetecteerd",
|
||||
"address_from_domain" : "Je adres is van unstoppable domain ${domain}"
|
||||
}
|
|
@ -488,5 +488,8 @@
|
|||
"unspent_coins_title" : "Niewydane monety",
|
||||
"unspent_coins_details_title" : "Szczegóły niewydanych monet",
|
||||
"freeze" : "Zamrażać",
|
||||
"coin_control" : "Kontrola monet (opcjonalnie)"
|
||||
"coin_control" : "Kontrola monet (opcjonalnie)",
|
||||
|
||||
"address_detected" : "Wykryto adres",
|
||||
"address_from_domain" : "Dostałeś adres od unstoppable domain ${domain}"
|
||||
}
|
|
@ -488,5 +488,8 @@
|
|||
"unspent_coins_title" : "Moedas não gastas",
|
||||
"unspent_coins_details_title" : "Detalhes de moedas não gastas",
|
||||
"freeze" : "Congelar",
|
||||
"coin_control" : "Controle de moedas (opcional)"
|
||||
"coin_control" : "Controle de moedas (opcional)",
|
||||
|
||||
"address_detected" : "Endereço detectado",
|
||||
"address_from_domain" : "Você obteve o endereço de unstoppable domain ${domain}"
|
||||
}
|
|
@ -488,5 +488,8 @@
|
|||
"unspent_coins_title" : "Неизрасходованные монеты",
|
||||
"unspent_coins_details_title" : "Сведения о неизрасходованных монетах",
|
||||
"freeze" : "Заморозить",
|
||||
"coin_control" : "Контроль монет (необязательно)"
|
||||
"coin_control" : "Контроль монет (необязательно)",
|
||||
|
||||
"address_detected" : "Обнаружен адрес",
|
||||
"address_from_domain" : "Вы получили адрес из unstoppable domain ${domain}"
|
||||
}
|
|
@ -488,5 +488,8 @@
|
|||
"unspent_coins_title" : "Невитрачені монети",
|
||||
"unspent_coins_details_title" : "Відомості про невитрачені монети",
|
||||
"freeze" : "Заморозити",
|
||||
"coin_control" : "Контроль монет (необов’язково)"
|
||||
"coin_control" : "Контроль монет (необов’язково)",
|
||||
|
||||
"address_detected" : "Виявлено адресу",
|
||||
"address_from_domain" : "Ви отримали адресу від unstoppable domain ${domain}"
|
||||
}
|
|
@ -488,5 +488,8 @@
|
|||
"unspent_coins_title" : "未使用的硬幣",
|
||||
"unspent_coins_details_title" : "未使用代幣詳情",
|
||||
"freeze" : "凍結",
|
||||
"coin_control" : "硬幣控制(可選)"
|
||||
"coin_control" : "硬幣控制(可選)",
|
||||
|
||||
"address_detected" : "檢測到地址",
|
||||
"address_from_domain" : "您有以下地址 unstoppable domain ${domain}"
|
||||
}
|
Loading…
Reference in a new issue