mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-22 10:45:08 +00:00
Merge branch 'main' into zano-pr
This commit is contained in:
commit
71e817fa8f
40 changed files with 2981 additions and 234 deletions
38
build-guide-win.md
Normal file
38
build-guide-win.md
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# Building CakeWallet for Windows
|
||||||
|
|
||||||
|
## Requirements and Setup
|
||||||
|
|
||||||
|
The following are the system requirements to build CakeWallet for your Windows PC.
|
||||||
|
|
||||||
|
```
|
||||||
|
Windows 10 or later (64-bit), x86-64 based
|
||||||
|
Flutter 3 or above
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building CakeWallet on Windows
|
||||||
|
|
||||||
|
These steps will help you configure and execute a build of CakeWallet from its source code.
|
||||||
|
|
||||||
|
### 1. Installing Package Dependencies
|
||||||
|
|
||||||
|
For build CakeWallet windows application from sources you will be needed to have:
|
||||||
|
> [Install Flutter]Follow installation guide (https://docs.flutter.dev/get-started/install/windows) and install do not miss to dev tools (install https://docs.flutter.dev/get-started/install/windows/desktop#development-tools) which are required for windows desktop development (need to install Git for Windows and Visual Studio 2022). Then install `Desktop development with C++` packages via GUI Visual Studio 2022, or Visual Studio Build Tools 2022 including: `C++ Build Tools core features`, `C++ 2022 Redistributable Update`, `C++ core desktop features`, `MVC v143 - VS 2022 C++ x64/x86 build tools`, `C++ CMake tools for Windwos`, `Testing tools core features - Build Tools`, `C++ AddressSanitizer`.
|
||||||
|
> [Install WSL] for building monero dependencies need to install Windows WSL (https://learn.microsoft.com/en-us/windows/wsl/install) and required packages for WSL (Ubuntu):
|
||||||
|
`$ sudo apt update `
|
||||||
|
`$ sudo apt build-essential cmake gcc-mingw-w64 g++-mingw-w64 autoconf libtool pkg-config`
|
||||||
|
|
||||||
|
### 2. Pull CakeWallet source code
|
||||||
|
|
||||||
|
You can downlaod CakeWallet source code from our [GitHub repository](github.com/cake-tech/cake_wallet) via git by following next command:
|
||||||
|
`$ git clone https://github.com/cake-tech/cake_wallet.git --branch MrCyjaneK-cyjan-monerodart`
|
||||||
|
OR you can download it as [Zip archive](https://github.com/cake-tech/cake_wallet/archive/refs/heads/MrCyjaneK-cyjan-monerodart.zip)
|
||||||
|
|
||||||
|
### 3. Build Monero, Monero_c and their dependencies
|
||||||
|
|
||||||
|
For use monero in the application need to build Monero wrapper - Monero_C which will be used by monero.dart package. For that need to run shell (bash - typically same named utility should be available after WSL is enabled in your system) with previously installed WSL, then change current directory to the application project directory with your used shell and then change current directory to `scripts/windows`: `$ cd scripts/windows`. Run build script: `$ ./build_all.sh`.
|
||||||
|
|
||||||
|
### 4. Configure and build CakeWallet application
|
||||||
|
|
||||||
|
To configure the application open directory where you have downloaded or unarchived CakeWallet sources and run `cakewallet.bat`.
|
||||||
|
Or if you used WSL and have active shell session you can run `$ ./cakewallet.sh` script in `scripts/windows` which will run `cakewallet.bat` in WSL.
|
||||||
|
After execution of `cakewallet.bat` you should to get `Cake Wallet.zip` in project root directory which will contains `CakeWallet.exe` file and another needed files for run the application. Now you can extract files from `Cake Wallet.zip` archive and run the application.
|
|
@ -394,10 +394,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_web_bluetooth
|
name: flutter_web_bluetooth
|
||||||
sha256: "52ce64f65d7321c4bf6abfe9dac02fb888731339a5e0ad6de59fb916c20c9f02"
|
sha256: fcd03e2e5f82edcedcbc940f1b6a0635a50757374183254f447640886c53208e
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.3"
|
version: "0.2.4"
|
||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -568,7 +568,7 @@ packages:
|
||||||
description:
|
description:
|
||||||
path: "packages/ledger-bitcoin"
|
path: "packages/ledger-bitcoin"
|
||||||
ref: HEAD
|
ref: HEAD
|
||||||
resolved-ref: dbb5c4956949dc734af3fc8febdbabed89da72aa
|
resolved-ref: "07cd61ef76a2a017b6d5ef233396740163265457"
|
||||||
url: "https://github.com/cake-tech/ledger-flutter-plus-plugins"
|
url: "https://github.com/cake-tech/ledger-flutter-plus-plugins"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.3"
|
version: "0.0.3"
|
||||||
|
@ -585,7 +585,7 @@ packages:
|
||||||
description:
|
description:
|
||||||
path: "packages/ledger-litecoin"
|
path: "packages/ledger-litecoin"
|
||||||
ref: HEAD
|
ref: HEAD
|
||||||
resolved-ref: dbb5c4956949dc734af3fc8febdbabed89da72aa
|
resolved-ref: "07cd61ef76a2a017b6d5ef233396740163265457"
|
||||||
url: "https://github.com/cake-tech/ledger-flutter-plus-plugins"
|
url: "https://github.com/cake-tech/ledger-flutter-plus-plugins"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.2"
|
version: "0.0.2"
|
||||||
|
|
|
@ -7,6 +7,7 @@ enum DeviceConnectionType {
|
||||||
static List<DeviceConnectionType> supportedConnectionTypes(WalletType walletType,
|
static List<DeviceConnectionType> supportedConnectionTypes(WalletType walletType,
|
||||||
[bool isIOS = false]) {
|
[bool isIOS = false]) {
|
||||||
switch (walletType) {
|
switch (walletType) {
|
||||||
|
case WalletType.monero:
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
|
|
|
@ -61,4 +61,8 @@ abstract class WalletService<N extends WalletCredentials, RFS extends WalletCred
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the Wallet requires a hardware wallet to be connected during
|
||||||
|
/// the opening flow. (Currently only the case for Monero)
|
||||||
|
bool requireHardwareWalletConnection(String name) => false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ Future<bool> setupNodeSync(
|
||||||
daemonUsername: login ?? '',
|
daemonUsername: login ?? '',
|
||||||
daemonPassword: password ?? '');
|
daemonPassword: password ?? '');
|
||||||
});
|
});
|
||||||
// monero.Wallet_init3(wptr!, argv0: '', defaultLogBaseName: 'moneroc', console: true);
|
// monero.Wallet_init3(wptr!, argv0: '', defaultLogBaseName: 'moneroc', console: true, logPath: '');
|
||||||
|
|
||||||
final status = monero.Wallet_status(wptr!);
|
final status = monero.Wallet_status(wptr!);
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,9 @@ import 'package:cw_monero/api/exceptions/wallet_creation_exception.dart';
|
||||||
import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
|
import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
|
||||||
import 'package:cw_monero/api/exceptions/wallet_restore_from_keys_exception.dart';
|
import 'package:cw_monero/api/exceptions/wallet_restore_from_keys_exception.dart';
|
||||||
import 'package:cw_monero/api/exceptions/wallet_restore_from_seed_exception.dart';
|
import 'package:cw_monero/api/exceptions/wallet_restore_from_seed_exception.dart';
|
||||||
import 'package:cw_monero/api/wallet.dart';
|
|
||||||
import 'package:cw_monero/api/transaction_history.dart';
|
import 'package:cw_monero/api/transaction_history.dart';
|
||||||
|
import 'package:cw_monero/api/wallet.dart';
|
||||||
|
import 'package:cw_monero/ledger.dart';
|
||||||
import 'package:monero/monero.dart' as monero;
|
import 'package:monero/monero.dart' as monero;
|
||||||
|
|
||||||
class MoneroCException implements Exception {
|
class MoneroCException implements Exception {
|
||||||
|
@ -17,9 +18,7 @@ class MoneroCException implements Exception {
|
||||||
MoneroCException(this.message);
|
MoneroCException(this.message);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() => message;
|
||||||
return message;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkIfMoneroCIsFine() {
|
void checkIfMoneroCIsFine() {
|
||||||
|
@ -43,7 +42,6 @@ void checkIfMoneroCIsFine() {
|
||||||
throw MoneroCException("monero_c and monero.dart wrapper export list mismatch.\nLogic errors can occur.\nRefusing to run in release mode.\ncpp: '$cppCsExp'\ndart: '$dartCsExp'");
|
throw MoneroCException("monero_c and monero.dart wrapper export list mismatch.\nLogic errors can occur.\nRefusing to run in release mode.\ncpp: '$cppCsExp'\ndart: '$dartCsExp'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
monero.WalletManager? _wmPtr;
|
monero.WalletManager? _wmPtr;
|
||||||
final monero.WalletManager wmPtr = Pointer.fromAddress((() {
|
final monero.WalletManager wmPtr = Pointer.fromAddress((() {
|
||||||
try {
|
try {
|
||||||
|
@ -60,6 +58,13 @@ final monero.WalletManager wmPtr = Pointer.fromAddress((() {
|
||||||
return _wmPtr!.address;
|
return _wmPtr!.address;
|
||||||
})());
|
})());
|
||||||
|
|
||||||
|
void createWalletPointer() {
|
||||||
|
final newWptr = monero.WalletManager_createWallet(wmPtr,
|
||||||
|
path: "", password: "", language: "", networkType: 0);
|
||||||
|
|
||||||
|
wptr = newWptr;
|
||||||
|
}
|
||||||
|
|
||||||
void createWalletSync(
|
void createWalletSync(
|
||||||
{required String path,
|
{required String path,
|
||||||
required String password,
|
required String password,
|
||||||
|
@ -124,13 +129,13 @@ void restoreWalletFromKeysSync(
|
||||||
int restoreHeight = 0}) {
|
int restoreHeight = 0}) {
|
||||||
txhistory = null;
|
txhistory = null;
|
||||||
var newWptr = (spendKey != "")
|
var newWptr = (spendKey != "")
|
||||||
? monero.WalletManager_createDeterministicWalletFromSpendKey(
|
? monero.WalletManager_createDeterministicWalletFromSpendKey(wmPtr,
|
||||||
wmPtr,
|
|
||||||
path: path,
|
path: path,
|
||||||
password: password,
|
password: password,
|
||||||
language: language,
|
language: language,
|
||||||
spendKeyString: spendKey,
|
spendKeyString: spendKey,
|
||||||
newWallet: true, // TODO(mrcyjanek): safe to remove
|
newWallet: true,
|
||||||
|
// TODO(mrcyjanek): safe to remove
|
||||||
restoreHeight: restoreHeight)
|
restoreHeight: restoreHeight)
|
||||||
: monero.WalletManager_createWalletFromKeys(
|
: monero.WalletManager_createWalletFromKeys(
|
||||||
wmPtr,
|
wmPtr,
|
||||||
|
@ -156,7 +161,7 @@ void restoreWalletFromKeysSync(
|
||||||
if (viewKey != viewKeyRestored && viewKey != "") {
|
if (viewKey != viewKeyRestored && viewKey != "") {
|
||||||
monero.WalletManager_closeWallet(wmPtr, newWptr, false);
|
monero.WalletManager_closeWallet(wmPtr, newWptr, false);
|
||||||
File(path).deleteSync();
|
File(path).deleteSync();
|
||||||
File(path+".keys").deleteSync();
|
File(path + ".keys").deleteSync();
|
||||||
newWptr = monero.WalletManager_createWalletFromKeys(
|
newWptr = monero.WalletManager_createWalletFromKeys(
|
||||||
wmPtr,
|
wmPtr,
|
||||||
path: path,
|
path: path,
|
||||||
|
@ -230,41 +235,39 @@ void restoreWalletFromSpendKeySync(
|
||||||
|
|
||||||
String _lastOpenedWallet = "";
|
String _lastOpenedWallet = "";
|
||||||
|
|
||||||
// void restoreMoneroWalletFromDevice(
|
Future<void> restoreWalletFromHardwareWallet(
|
||||||
// {required String path,
|
{required String path,
|
||||||
// required String password,
|
required String password,
|
||||||
// required String deviceName,
|
required String deviceName,
|
||||||
// int nettype = 0,
|
int nettype = 0,
|
||||||
// int restoreHeight = 0}) {
|
int restoreHeight = 0}) async {
|
||||||
//
|
txhistory = null;
|
||||||
// final pathPointer = path.toNativeUtf8();
|
|
||||||
// final passwordPointer = password.toNativeUtf8();
|
final newWptrAddr = await Isolate.run(() {
|
||||||
// final deviceNamePointer = deviceName.toNativeUtf8();
|
return monero.WalletManager_createWalletFromDevice(wmPtr,
|
||||||
// final errorMessagePointer = ''.toNativeUtf8();
|
path: path,
|
||||||
//
|
password: password,
|
||||||
// final isWalletRestored = restoreWalletFromDeviceNative(
|
restoreHeight: restoreHeight,
|
||||||
// pathPointer,
|
deviceName: deviceName)
|
||||||
// passwordPointer,
|
.address;
|
||||||
// deviceNamePointer,
|
});
|
||||||
// nettype,
|
final newWptr = Pointer<Void>.fromAddress(newWptrAddr);
|
||||||
// restoreHeight,
|
|
||||||
// errorMessagePointer) != 0;
|
final status = monero.Wallet_status(newWptr);
|
||||||
//
|
|
||||||
// calloc.free(pathPointer);
|
if (status != 0) {
|
||||||
// calloc.free(passwordPointer);
|
final error = monero.Wallet_errorString(newWptr);
|
||||||
//
|
throw WalletRestoreFromSeedException(message: error);
|
||||||
// storeSync();
|
}
|
||||||
//
|
wptr = newWptr;
|
||||||
// if (!isWalletRestored) {
|
|
||||||
// throw WalletRestoreFromKeysException(
|
openedWalletsByPath[path] = wptr!;
|
||||||
// message: convertUTF8ToString(pointer: errorMessagePointer));
|
}
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
Map<String, monero.wallet> openedWalletsByPath = {};
|
Map<String, monero.wallet> openedWalletsByPath = {};
|
||||||
|
|
||||||
void loadWallet(
|
Future<void> loadWallet(
|
||||||
{required String path, required String password, int nettype = 0}) {
|
{required String path, required String password, int nettype = 0}) async {
|
||||||
if (openedWalletsByPath[path] != null) {
|
if (openedWalletsByPath[path] != null) {
|
||||||
txhistory = null;
|
txhistory = null;
|
||||||
wptr = openedWalletsByPath[path]!;
|
wptr = openedWalletsByPath[path]!;
|
||||||
|
@ -278,8 +281,29 @@ void loadWallet(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
txhistory = null;
|
txhistory = null;
|
||||||
final newWptr = monero.WalletManager_openWallet(wmPtr,
|
|
||||||
path: path, password: password);
|
/// Get the device type
|
||||||
|
/// 0: Software Wallet
|
||||||
|
/// 1: Ledger
|
||||||
|
/// 2: Trezor
|
||||||
|
final deviceType = monero.WalletManager_queryWalletDevice(wmPtr,
|
||||||
|
keysFileName: "$path.keys", password: password, kdfRounds: 1);
|
||||||
|
|
||||||
|
if (deviceType == 1) {
|
||||||
|
final dummyWPtr = wptr ??
|
||||||
|
monero.WalletManager_openWallet(wmPtr, path: '', password: '');
|
||||||
|
enableLedgerExchange(dummyWPtr, gLedger!);
|
||||||
|
}
|
||||||
|
|
||||||
|
final addr = wmPtr.address;
|
||||||
|
final newWptrAddr = await Isolate.run(() {
|
||||||
|
return monero.WalletManager_openWallet(Pointer.fromAddress(addr),
|
||||||
|
path: path, password: password)
|
||||||
|
.address;
|
||||||
|
});
|
||||||
|
|
||||||
|
final newWptr = Pointer<Void>.fromAddress(newWptrAddr);
|
||||||
|
|
||||||
_lastOpenedWallet = path;
|
_lastOpenedWallet = path;
|
||||||
final status = monero.Wallet_status(newWptr);
|
final status = monero.Wallet_status(newWptr);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
|
@ -287,6 +311,7 @@ void loadWallet(
|
||||||
print(err);
|
print(err);
|
||||||
throw WalletOpeningException(message: err);
|
throw WalletOpeningException(message: err);
|
||||||
}
|
}
|
||||||
|
|
||||||
wptr = newWptr;
|
wptr = newWptr;
|
||||||
openedWalletsByPath[path] = wptr!;
|
openedWalletsByPath[path] = wptr!;
|
||||||
}
|
}
|
||||||
|
@ -351,7 +376,7 @@ Future<void> _openWallet(Map<String, String> args) async => loadWallet(
|
||||||
|
|
||||||
bool _isWalletExist(String path) => isWalletExistSync(path: path);
|
bool _isWalletExist(String path) => isWalletExistSync(path: path);
|
||||||
|
|
||||||
void openWallet(
|
Future<void> openWallet(
|
||||||
{required String path,
|
{required String path,
|
||||||
required String password,
|
required String password,
|
||||||
int nettype = 0}) async =>
|
int nettype = 0}) async =>
|
||||||
|
|
88
cw_monero/lib/ledger.dart
Normal file
88
cw_monero/lib/ledger.dart
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
|
import 'package:ledger_flutter_plus/ledger_flutter_plus_dart.dart';
|
||||||
|
import 'package:monero/monero.dart' as monero;
|
||||||
|
// import 'package:polyseed/polyseed.dart';
|
||||||
|
|
||||||
|
LedgerConnection? gLedger;
|
||||||
|
|
||||||
|
Timer? _ledgerExchangeTimer;
|
||||||
|
Timer? _ledgerKeepAlive;
|
||||||
|
|
||||||
|
void enableLedgerExchange(monero.wallet ptr, LedgerConnection connection) {
|
||||||
|
_ledgerExchangeTimer?.cancel();
|
||||||
|
_ledgerExchangeTimer = Timer.periodic(Duration(milliseconds: 1), (_) async {
|
||||||
|
final ledgerRequestLength = monero.Wallet_getSendToDeviceLength(ptr);
|
||||||
|
final ledgerRequest = monero.Wallet_getSendToDevice(ptr)
|
||||||
|
.cast<Uint8>()
|
||||||
|
.asTypedList(ledgerRequestLength);
|
||||||
|
if (ledgerRequestLength > 0) {
|
||||||
|
_ledgerKeepAlive?.cancel();
|
||||||
|
|
||||||
|
final Pointer<Uint8> emptyPointer = malloc<Uint8>(0);
|
||||||
|
monero.Wallet_setDeviceSendData(
|
||||||
|
ptr, emptyPointer.cast<UnsignedChar>(), 0);
|
||||||
|
malloc.free(emptyPointer);
|
||||||
|
|
||||||
|
// print("> ${ledgerRequest.toHexString()}");
|
||||||
|
final response = await exchange(connection, ledgerRequest);
|
||||||
|
// print("< ${response.toHexString()}");
|
||||||
|
|
||||||
|
final Pointer<Uint8> result = malloc<Uint8>(response.length);
|
||||||
|
for (var i = 0; i < response.length; i++) {
|
||||||
|
result.asTypedList(response.length)[i] = response[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
monero.Wallet_setDeviceReceivedData(
|
||||||
|
ptr, result.cast<UnsignedChar>(), response.length);
|
||||||
|
malloc.free(result);
|
||||||
|
keepAlive(connection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void keepAlive(LedgerConnection connection) {
|
||||||
|
if (connection.connectionType == ConnectionType.ble) {
|
||||||
|
UniversalBle.onConnectionChange = (String deviceId, bool isConnected) {
|
||||||
|
print("[Monero] Ledger Disconnected");
|
||||||
|
_ledgerKeepAlive?.cancel();
|
||||||
|
};
|
||||||
|
_ledgerKeepAlive = Timer.periodic(Duration(seconds: 10), (_) async {
|
||||||
|
try {
|
||||||
|
UniversalBle.setNotifiable(
|
||||||
|
connection.device.id,
|
||||||
|
connection.device.deviceInfo.serviceId,
|
||||||
|
connection.device.deviceInfo.notifyCharacteristicKey,
|
||||||
|
BleInputProperty.notification,
|
||||||
|
);
|
||||||
|
} catch (_){}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void disableLedgerExchange() {
|
||||||
|
_ledgerExchangeTimer?.cancel();
|
||||||
|
_ledgerKeepAlive?.cancel();
|
||||||
|
gLedger?.disconnect();
|
||||||
|
gLedger = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Uint8List> exchange(LedgerConnection connection, Uint8List data) async =>
|
||||||
|
connection.sendOperation<Uint8List>(ExchangeOperation(data));
|
||||||
|
|
||||||
|
class ExchangeOperation extends LedgerRawOperation<Uint8List> {
|
||||||
|
final Uint8List inputData;
|
||||||
|
|
||||||
|
ExchangeOperation(this.inputData);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> read(ByteDataReader reader) async =>
|
||||||
|
reader.read(reader.remainingLength);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<Uint8List>> write(ByteDataWriter writer) async => [inputData];
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ import 'package:cw_monero/api/wallet.dart' as monero_wallet;
|
||||||
import 'package:cw_monero/api/wallet_manager.dart';
|
import 'package:cw_monero/api/wallet_manager.dart';
|
||||||
import 'package:cw_monero/exceptions/monero_transaction_creation_exception.dart';
|
import 'package:cw_monero/exceptions/monero_transaction_creation_exception.dart';
|
||||||
import 'package:cw_monero/exceptions/monero_transaction_no_inputs_exception.dart';
|
import 'package:cw_monero/exceptions/monero_transaction_no_inputs_exception.dart';
|
||||||
|
import 'package:cw_monero/ledger.dart';
|
||||||
import 'package:cw_monero/monero_transaction_creation_credentials.dart';
|
import 'package:cw_monero/monero_transaction_creation_credentials.dart';
|
||||||
import 'package:cw_monero/monero_transaction_history.dart';
|
import 'package:cw_monero/monero_transaction_history.dart';
|
||||||
import 'package:cw_monero/monero_transaction_info.dart';
|
import 'package:cw_monero/monero_transaction_info.dart';
|
||||||
|
@ -36,6 +37,7 @@ import 'package:cw_monero/monero_wallet_addresses.dart';
|
||||||
import 'package:cw_monero/pending_monero_transaction.dart';
|
import 'package:cw_monero/pending_monero_transaction.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:monero/monero.dart' as monero;
|
import 'package:monero/monero.dart' as monero;
|
||||||
|
|
||||||
|
@ -828,4 +830,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
return monero_wallet.verifyMessage(message, address, signature);
|
return monero_wallet.verifyMessage(message, address, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setLedgerConnection(LedgerConnection connection) {
|
||||||
|
final dummyWPtr = wptr ??
|
||||||
|
monero.WalletManager_openWallet(wmPtr, path: '', password: '');
|
||||||
|
enableLedgerExchange(dummyWPtr, connection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,13 @@ import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_service.dart';
|
import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:cw_core/get_height_by_date.dart';
|
import 'package:cw_core/get_height_by_date.dart';
|
||||||
|
import 'package:cw_monero/api/account_list.dart';
|
||||||
import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
|
import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
|
||||||
import 'package:cw_monero/api/wallet_manager.dart';
|
import 'package:cw_monero/api/wallet_manager.dart';
|
||||||
|
import 'package:cw_monero/ledger.dart';
|
||||||
import 'package:cw_monero/monero_wallet.dart';
|
import 'package:cw_monero/monero_wallet.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
import 'package:polyseed/polyseed.dart';
|
import 'package:polyseed/polyseed.dart';
|
||||||
import 'package:monero/monero.dart' as monero;
|
import 'package:monero/monero.dart' as monero;
|
||||||
|
|
||||||
|
@ -25,6 +28,15 @@ class MoneroNewWalletCredentials extends WalletCredentials {
|
||||||
final bool isPolyseed;
|
final bool isPolyseed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MoneroRestoreWalletFromHardwareCredentials extends WalletCredentials {
|
||||||
|
MoneroRestoreWalletFromHardwareCredentials({required String name,
|
||||||
|
required this.ledgerConnection,
|
||||||
|
int height = 0,
|
||||||
|
String? password})
|
||||||
|
: super(name: name, password: password, height: height);
|
||||||
|
LedgerConnection ledgerConnection;
|
||||||
|
}
|
||||||
|
|
||||||
class MoneroRestoreWalletFromSeedCredentials extends WalletCredentials {
|
class MoneroRestoreWalletFromSeedCredentials extends WalletCredentials {
|
||||||
MoneroRestoreWalletFromSeedCredentials(
|
MoneroRestoreWalletFromSeedCredentials(
|
||||||
{required String name, required this.mnemonic, int height = 0, String? password})
|
{required String name, required this.mnemonic, int height = 0, String? password})
|
||||||
|
@ -39,8 +51,7 @@ class MoneroWalletLoadingException implements Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MoneroRestoreWalletFromKeysCredentials extends WalletCredentials {
|
class MoneroRestoreWalletFromKeysCredentials extends WalletCredentials {
|
||||||
MoneroRestoreWalletFromKeysCredentials(
|
MoneroRestoreWalletFromKeysCredentials({required String name,
|
||||||
{required String name,
|
|
||||||
required String password,
|
required String password,
|
||||||
required this.language,
|
required this.language,
|
||||||
required this.address,
|
required this.address,
|
||||||
|
@ -59,7 +70,7 @@ class MoneroWalletService extends WalletService<
|
||||||
MoneroNewWalletCredentials,
|
MoneroNewWalletCredentials,
|
||||||
MoneroRestoreWalletFromSeedCredentials,
|
MoneroRestoreWalletFromSeedCredentials,
|
||||||
MoneroRestoreWalletFromKeysCredentials,
|
MoneroRestoreWalletFromKeysCredentials,
|
||||||
MoneroNewWalletCredentials> {
|
MoneroRestoreWalletFromHardwareCredentials> {
|
||||||
MoneroWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
|
MoneroWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
|
||||||
|
|
||||||
final Box<WalletInfo> walletInfoSource;
|
final Box<WalletInfo> walletInfoSource;
|
||||||
|
@ -185,8 +196,7 @@ class MoneroWalletService extends WalletService<
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> rename(
|
Future<void> rename(String currentName, String password, String newName) async {
|
||||||
String currentName, String password, String newName) async {
|
|
||||||
final currentWalletInfo = walletInfoSource.values.firstWhere(
|
final currentWalletInfo = walletInfoSource.values.firstWhere(
|
||||||
(info) => info.id == WalletBase.idFor(currentName, getType()));
|
(info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||||
final currentWallet = MoneroWallet(
|
final currentWallet = MoneroWallet(
|
||||||
|
@ -232,9 +242,34 @@ class MoneroWalletService extends WalletService<
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<MoneroWallet> restoreFromHardwareWallet(MoneroNewWalletCredentials credentials) {
|
Future<MoneroWallet> restoreFromHardwareWallet(
|
||||||
throw UnimplementedError(
|
MoneroRestoreWalletFromHardwareCredentials credentials) async {
|
||||||
"Restoring a Monero wallet from a hardware wallet is not yet supported!");
|
try {
|
||||||
|
final path = await pathForWallet(name: credentials.name, type: getType());
|
||||||
|
final password = credentials.password;
|
||||||
|
final height = credentials.height;
|
||||||
|
|
||||||
|
if (wptr == null ) monero_wallet_manager.createWalletPointer();
|
||||||
|
|
||||||
|
enableLedgerExchange(wptr!, credentials.ledgerConnection);
|
||||||
|
await monero_wallet_manager.restoreWalletFromHardwareWallet(
|
||||||
|
path: path,
|
||||||
|
password: password!,
|
||||||
|
restoreHeight: height!,
|
||||||
|
deviceName: 'Ledger');
|
||||||
|
|
||||||
|
final wallet = MoneroWallet(
|
||||||
|
walletInfo: credentials.walletInfo!,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
password: credentials.password!);
|
||||||
|
await wallet.init();
|
||||||
|
|
||||||
|
return wallet;
|
||||||
|
} catch (e) {
|
||||||
|
// TODO: Implement Exception for wallet list service.
|
||||||
|
print('MoneroWalletsManager Error: $e');
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -283,8 +318,8 @@ class MoneroWalletService extends WalletService<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<MoneroWallet> _restoreFromPolyseed(
|
Future<MoneroWallet> _restoreFromPolyseed(String path, String password, Polyseed polyseed,
|
||||||
String path, String password, Polyseed polyseed, WalletInfo walletInfo, PolyseedLang lang,
|
WalletInfo walletInfo, PolyseedLang lang,
|
||||||
{PolyseedCoin coin = PolyseedCoin.POLYSEED_MONERO, int? overrideHeight}) async {
|
{PolyseedCoin coin = PolyseedCoin.POLYSEED_MONERO, int? overrideHeight}) async {
|
||||||
final height = overrideHeight ??
|
final height = overrideHeight ??
|
||||||
getMoneroHeigthByDate(date: DateTime.fromMillisecondsSinceEpoch(polyseed.birthday * 1000));
|
getMoneroHeigthByDate(date: DateTime.fromMillisecondsSinceEpoch(polyseed.birthday * 1000));
|
||||||
|
@ -329,7 +364,9 @@ class MoneroWalletService extends WalletService<
|
||||||
|
|
||||||
dir.listSync().forEach((f) {
|
dir.listSync().forEach((f) {
|
||||||
final file = File(f.path);
|
final file = File(f.path);
|
||||||
final name = f.path.split('/').last;
|
final name = f.path
|
||||||
|
.split('/')
|
||||||
|
.last;
|
||||||
final newPath = newWalletDirPath + '/$name';
|
final newPath = newWalletDirPath + '/$name';
|
||||||
final newFile = File(newPath);
|
final newFile = File(newPath);
|
||||||
|
|
||||||
|
@ -366,4 +403,11 @@ class MoneroWalletService extends WalletService<
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool requireHardwareWalletConnection(String name) {
|
||||||
|
final walletInfo = walletInfoSource.values
|
||||||
|
.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
|
||||||
|
return walletInfo.isHardwareWallet;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,10 +29,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: asn1lib
|
name: asn1lib
|
||||||
sha256: "58082b3f0dca697204dbab0ef9ff208bfaea7767ea771076af9a343488428dda"
|
sha256: "6b151826fcc95ff246cd219a0bf4c753ea14f4081ad71c61939becf3aba27f70"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.3"
|
version: "1.5.5"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -41,6 +41,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.11.0"
|
version: "2.11.0"
|
||||||
|
bluez:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: bluez
|
||||||
|
sha256: "203a1924e818a9dd74af2b2c7a8f375ab8e5edf0e486bba8f90a0d8a17ed9fce"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.8.2"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -217,6 +225,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.3"
|
version: "2.3.3"
|
||||||
|
dbus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dbus
|
||||||
|
sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.10"
|
||||||
encrypt:
|
encrypt:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -237,10 +253,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: ffi
|
name: ffi
|
||||||
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
|
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.3"
|
||||||
file:
|
file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -275,6 +291,14 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_web_bluetooth:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_web_bluetooth
|
||||||
|
sha256: "52ce64f65d7321c4bf6abfe9dac02fb888731339a5e0ad6de59fb916c20c9f02"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.3"
|
||||||
frontend_server_client:
|
frontend_server_client:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -303,18 +327,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: hashlib
|
name: hashlib
|
||||||
sha256: d41795742c10947930630118c6836608deeb9047cd05aee32d2baeb697afd66a
|
sha256: f572f2abce09fc7aee53f15927052b9732ea1053e540af8cae211111ee0b99b1
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.19.2"
|
version: "1.21.0"
|
||||||
hashlib_codecs:
|
hashlib_codecs:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: hashlib_codecs
|
name: hashlib_codecs
|
||||||
sha256: "2b570061f5a4b378425be28a576c1e11783450355ad4345a19f606ff3d96db0f"
|
sha256: "8cea9ccafcfeaa7324d2ae52c61c69f7ff71f4237507a018caab31b9e416e3b1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.0"
|
version: "2.6.0"
|
||||||
hive:
|
hive:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -335,10 +359,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
|
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.1"
|
version: "1.2.2"
|
||||||
http_multi_server:
|
http_multi_server:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -411,6 +435,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.1"
|
||||||
|
ledger_flutter_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: ledger_flutter_plus
|
||||||
|
sha256: c7b04008553193dbca7e17b430768eecc372a72b0ff3625b5e7fc5e5c8d3231b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.1"
|
||||||
|
ledger_usb_plus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: ledger_usb_plus
|
||||||
|
sha256: "21cc5d976cf7edb3518bd2a0c4164139cbb0817d2e4f2054707fc4edfdf9ce87"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -447,10 +487,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: mime
|
name: mime
|
||||||
sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2"
|
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "1.0.6"
|
||||||
mobx:
|
mobx:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -512,10 +552,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path_provider
|
name: path_provider
|
||||||
sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
|
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.3"
|
version: "2.1.4"
|
||||||
path_provider_android:
|
path_provider_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -552,10 +592,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_windows
|
name: path_provider_windows
|
||||||
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.1"
|
version: "2.3.0"
|
||||||
|
petitparser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: petitparser
|
||||||
|
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.2"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -628,6 +676,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.3"
|
version: "2.2.3"
|
||||||
|
rxdart:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: rxdart
|
||||||
|
sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.28.0"
|
||||||
shelf:
|
shelf:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -753,6 +809,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.2"
|
version: "1.3.2"
|
||||||
|
universal_ble:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: universal_ble
|
||||||
|
sha256: "0dfbd6b64bff3ad61ed7a895c232530d9614e9b01ab261a74433a43267edb7f3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.12.0"
|
||||||
|
universal_platform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: universal_platform
|
||||||
|
sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
unorm_dart:
|
unorm_dart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -801,22 +873,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.5"
|
version: "2.4.5"
|
||||||
win32:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: win32
|
|
||||||
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "5.5.0"
|
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: xdg_directories
|
name: xdg_directories
|
||||||
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
|
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.1.0"
|
||||||
|
xml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xml
|
||||||
|
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.5.0"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -827,4 +899,4 @@ packages:
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.3.0 <4.0.0"
|
dart: ">=3.3.0 <4.0.0"
|
||||||
flutter: ">=3.16.6"
|
flutter: ">=3.19.0"
|
||||||
|
|
|
@ -25,9 +25,10 @@ dependencies:
|
||||||
monero:
|
monero:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/mrcyjanek/monero_c
|
url: https://github.com/mrcyjanek/monero_c
|
||||||
ref: 5e93594f8d94d5723be25a7de71317e798e7a027 # monero_c hash
|
ref: 292bd2181ab048b2505126e52f32de5f7812e707 # monero_c hash
|
||||||
path: impls/monero.dart
|
path: impls/monero.dart
|
||||||
mutex: ^3.1.0
|
mutex: ^3.1.0
|
||||||
|
ledger_flutter_plus: ^1.4.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class ConnectionToNodeException implements Exception {
|
||||||
|
ConnectionToNodeException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
}
|
12
cw_wownero/lib/api/structs/account_row.dart
Normal file
12
cw_wownero/lib/api/structs/account_row.dart
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
class AccountRow extends Struct {
|
||||||
|
@Int64()
|
||||||
|
external int id;
|
||||||
|
|
||||||
|
external Pointer<Utf8> label;
|
||||||
|
|
||||||
|
String getLabel() => label.toDartString();
|
||||||
|
int getId() => id;
|
||||||
|
}
|
73
cw_wownero/lib/api/structs/coins_info_row.dart
Normal file
73
cw_wownero/lib/api/structs/coins_info_row.dart
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
class CoinsInfoRow extends Struct {
|
||||||
|
@Int64()
|
||||||
|
external int blockHeight;
|
||||||
|
|
||||||
|
external Pointer<Utf8> hash;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int internalOutputIndex;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int globalOutputIndex;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int spent;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int frozen;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int spentHeight;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int amount;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int rct;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int keyImageKnown;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int pkIndex;
|
||||||
|
|
||||||
|
@Uint32()
|
||||||
|
external int subaddrIndex;
|
||||||
|
|
||||||
|
@Uint32()
|
||||||
|
external int subaddrAccount;
|
||||||
|
|
||||||
|
external Pointer<Utf8> address;
|
||||||
|
|
||||||
|
external Pointer<Utf8> addressLabel;
|
||||||
|
|
||||||
|
external Pointer<Utf8> keyImage;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int unlockTime;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int unlocked;
|
||||||
|
|
||||||
|
external Pointer<Utf8> pubKey;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int coinbase;
|
||||||
|
|
||||||
|
external Pointer<Utf8> description;
|
||||||
|
|
||||||
|
String getHash() => hash.toDartString();
|
||||||
|
|
||||||
|
String getAddress() => address.toDartString();
|
||||||
|
|
||||||
|
String getAddressLabel() => addressLabel.toDartString();
|
||||||
|
|
||||||
|
String getKeyImage() => keyImage.toDartString();
|
||||||
|
|
||||||
|
String getPubKey() => pubKey.toDartString();
|
||||||
|
|
||||||
|
String getDescription() => description.toDartString();
|
||||||
|
}
|
15
cw_wownero/lib/api/structs/subaddress_row.dart
Normal file
15
cw_wownero/lib/api/structs/subaddress_row.dart
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
class SubaddressRow extends Struct {
|
||||||
|
@Int64()
|
||||||
|
external int id;
|
||||||
|
|
||||||
|
external Pointer<Utf8> address;
|
||||||
|
|
||||||
|
external Pointer<Utf8> label;
|
||||||
|
|
||||||
|
String getLabel() => label.toDartString();
|
||||||
|
String getAddress() => address.toDartString();
|
||||||
|
int getId() => id;
|
||||||
|
}
|
41
cw_wownero/lib/api/structs/transaction_info_row.dart
Normal file
41
cw_wownero/lib/api/structs/transaction_info_row.dart
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
class TransactionInfoRow extends Struct {
|
||||||
|
@Uint64()
|
||||||
|
external int amount;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int fee;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int blockHeight;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int confirmations;
|
||||||
|
|
||||||
|
@Uint32()
|
||||||
|
external int subaddrAccount;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int direction;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int isPending;
|
||||||
|
|
||||||
|
@Uint32()
|
||||||
|
external int subaddrIndex;
|
||||||
|
|
||||||
|
external Pointer<Utf8> hash;
|
||||||
|
|
||||||
|
external Pointer<Utf8> paymentId;
|
||||||
|
|
||||||
|
@Int64()
|
||||||
|
external int datetime;
|
||||||
|
|
||||||
|
int getDatetime() => datetime;
|
||||||
|
int getAmount() => amount >= 0 ? amount : amount * -1;
|
||||||
|
bool getIsPending() => isPending != 0;
|
||||||
|
String getHash() => hash.toDartString();
|
||||||
|
String getPaymentId() => paymentId.toDartString();
|
||||||
|
}
|
8
cw_wownero/lib/api/structs/ut8_box.dart
Normal file
8
cw_wownero/lib/api/structs/ut8_box.dart
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
class Utf8Box extends Struct {
|
||||||
|
external Pointer<Utf8> value;
|
||||||
|
|
||||||
|
String getValue() => value.toDartString();
|
||||||
|
}
|
8
cw_wownero/lib/cw_wownero.dart
Normal file
8
cw_wownero/lib/cw_wownero.dart
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
import 'cw_wownero_platform_interface.dart';
|
||||||
|
|
||||||
|
class CwWownero {
|
||||||
|
Future<String?> getPlatformVersion() {
|
||||||
|
return CwWowneroPlatform.instance.getPlatformVersion();
|
||||||
|
}
|
||||||
|
}
|
17
cw_wownero/lib/cw_wownero_method_channel.dart
Normal file
17
cw_wownero/lib/cw_wownero_method_channel.dart
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
import 'cw_wownero_platform_interface.dart';
|
||||||
|
|
||||||
|
/// An implementation of [CwWowneroPlatform] that uses method channels.
|
||||||
|
class MethodChannelCwWownero extends CwWowneroPlatform {
|
||||||
|
/// The method channel used to interact with the native platform.
|
||||||
|
@visibleForTesting
|
||||||
|
final methodChannel = const MethodChannel('cw_wownero');
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String?> getPlatformVersion() async {
|
||||||
|
final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
}
|
29
cw_wownero/lib/cw_wownero_platform_interface.dart
Normal file
29
cw_wownero/lib/cw_wownero_platform_interface.dart
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||||||
|
|
||||||
|
import 'cw_wownero_method_channel.dart';
|
||||||
|
|
||||||
|
abstract class CwWowneroPlatform extends PlatformInterface {
|
||||||
|
/// Constructs a CwWowneroPlatform.
|
||||||
|
CwWowneroPlatform() : super(token: _token);
|
||||||
|
|
||||||
|
static final Object _token = Object();
|
||||||
|
|
||||||
|
static CwWowneroPlatform _instance = MethodChannelCwWownero();
|
||||||
|
|
||||||
|
/// The default instance of [CwWowneroPlatform] to use.
|
||||||
|
///
|
||||||
|
/// Defaults to [MethodChannelCwWownero].
|
||||||
|
static CwWowneroPlatform get instance => _instance;
|
||||||
|
|
||||||
|
/// Platform-specific implementations should set this with their own
|
||||||
|
/// platform-specific class that extends [CwWowneroPlatform] when
|
||||||
|
/// they register themselves.
|
||||||
|
static set instance(CwWowneroPlatform instance) {
|
||||||
|
PlatformInterface.verifyToken(instance, _token);
|
||||||
|
_instance = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String?> getPlatformVersion() {
|
||||||
|
throw UnimplementedError('platformVersion() has not been implemented.');
|
||||||
|
}
|
||||||
|
}
|
1689
cw_wownero/lib/mywownero.dart
Normal file
1689
cw_wownero/lib/mywownero.dart
Normal file
File diff suppressed because it is too large
Load diff
|
@ -41,6 +41,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.11.0"
|
version: "2.11.0"
|
||||||
|
bluez:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: bluez
|
||||||
|
sha256: "203a1924e818a9dd74af2b2c7a8f375ab8e5edf0e486bba8f90a0d8a17ed9fce"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.8.2"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -217,6 +225,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.3"
|
version: "2.3.3"
|
||||||
|
dbus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dbus
|
||||||
|
sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.10"
|
||||||
encrypt:
|
encrypt:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -275,6 +291,14 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_web_bluetooth:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_web_bluetooth
|
||||||
|
sha256: "52ce64f65d7321c4bf6abfe9dac02fb888731339a5e0ad6de59fb916c20c9f02"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.3"
|
||||||
frontend_server_client:
|
frontend_server_client:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -411,6 +435,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.1"
|
||||||
|
ledger_flutter_plus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: ledger_flutter_plus
|
||||||
|
sha256: ea3ed586e1697776dacf42ac979095f1ca3bd143bf007cbe5c78e09cb6943f42
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.5"
|
||||||
|
ledger_usb_plus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: ledger_usb_plus
|
||||||
|
sha256: "21cc5d976cf7edb3518bd2a0c4164139cbb0817d2e4f2054707fc4edfdf9ce87"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -548,6 +588,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.1"
|
version: "2.2.1"
|
||||||
|
petitparser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: petitparser
|
||||||
|
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.2"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -560,10 +608,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a
|
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.3"
|
version: "2.1.8"
|
||||||
pointycastle:
|
pointycastle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -612,6 +660,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.3"
|
version: "2.2.3"
|
||||||
|
rxdart:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: rxdart
|
||||||
|
sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.28.0"
|
||||||
shelf:
|
shelf:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -737,6 +793,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.1"
|
version: "1.3.1"
|
||||||
|
universal_ble:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: universal_ble
|
||||||
|
sha256: "0dfbd6b64bff3ad61ed7a895c232530d9614e9b01ab261a74433a43267edb7f3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.12.0"
|
||||||
|
universal_platform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: universal_platform
|
||||||
|
sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
unorm_dart:
|
unorm_dart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -793,6 +865,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
|
xml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xml
|
||||||
|
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.5.0"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -802,5 +882,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.1"
|
version: "3.1.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.2.0-0 <4.0.0"
|
dart: ">=3.3.0 <4.0.0"
|
||||||
flutter: ">=3.7.0"
|
flutter: ">=3.19.0"
|
||||||
|
|
|
@ -25,7 +25,7 @@ dependencies:
|
||||||
monero:
|
monero:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/mrcyjanek/monero_c
|
url: https://github.com/mrcyjanek/monero_c
|
||||||
ref: 5e93594f8d94d5723be25a7de71317e798e7a027 # monero_c hash
|
ref: 292bd2181ab048b2505126e52f32de5f7812e707 # monero_c hash
|
||||||
path: impls/monero.dart
|
path: impls/monero.dart
|
||||||
mutex: ^3.1.0
|
mutex: ^3.1.0
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,11 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
class WalletLoadingService {
|
class WalletLoadingService {
|
||||||
WalletLoadingService(this.sharedPreferences, this.keyService, this.walletServiceFactory);
|
WalletLoadingService(
|
||||||
|
this.sharedPreferences,
|
||||||
|
this.keyService,
|
||||||
|
this.walletServiceFactory,
|
||||||
|
);
|
||||||
|
|
||||||
final SharedPreferences sharedPreferences;
|
final SharedPreferences sharedPreferences;
|
||||||
final KeyService keyService;
|
final KeyService keyService;
|
||||||
|
@ -77,7 +81,8 @@ class WalletLoadingService {
|
||||||
await updateMoneroWalletPassword(wallet);
|
await updateMoneroWalletPassword(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
await sharedPreferences.setString(PreferencesKey.currentWalletName, wallet.name);
|
await sharedPreferences.setString(
|
||||||
|
PreferencesKey.currentWalletName, wallet.name);
|
||||||
await sharedPreferences.setInt(
|
await sharedPreferences.setInt(
|
||||||
PreferencesKey.currentWalletType, serializeToInt(wallet.type));
|
PreferencesKey.currentWalletType, serializeToInt(wallet.type));
|
||||||
|
|
||||||
|
@ -129,4 +134,9 @@ class WalletLoadingService {
|
||||||
|
|
||||||
return "\n\n$type ($name): ${await walletService.getSeeds(name, password, type)}";
|
return "\n\n$type ($name): ${await walletService.getSeeds(name, password, type)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool requireHardwareWalletConnection(WalletType type, String name) {
|
||||||
|
final walletService = walletServiceFactory.call(type);
|
||||||
|
return walletService.requireHardwareWalletConnection(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,12 +32,14 @@ import 'package:cake_wallet/entities/biometric_auth.dart';
|
||||||
import 'package:cake_wallet/entities/contact.dart';
|
import 'package:cake_wallet/entities/contact.dart';
|
||||||
import 'package:cake_wallet/entities/contact_record.dart';
|
import 'package:cake_wallet/entities/contact_record.dart';
|
||||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||||
|
import 'package:cake_wallet/entities/hardware_wallet/require_hardware_wallet_connection.dart';
|
||||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||||
import 'package:cake_wallet/entities/wallet_edit_page_arguments.dart';
|
import 'package:cake_wallet/entities/wallet_edit_page_arguments.dart';
|
||||||
import 'package:cake_wallet/entities/wallet_manager.dart';
|
import 'package:cake_wallet/entities/wallet_manager.dart';
|
||||||
import 'package:cake_wallet/src/screens/buy/buy_sell_options_page.dart';
|
import 'package:cake_wallet/src/screens/buy/buy_sell_options_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/buy/payment_method_options_page.dart';
|
import 'package:cake_wallet/src/screens/buy/payment_method_options_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/receive/address_list_page.dart';
|
import 'package:cake_wallet/src/screens/receive/address_list_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/mweb_logs_page.dart';
|
import 'package:cake_wallet/src/screens/settings/mweb_logs_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/mweb_node_page.dart';
|
import 'package:cake_wallet/src/screens/settings/mweb_node_page.dart';
|
||||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||||
|
@ -184,7 +186,6 @@ import 'package:cake_wallet/src/screens/transaction_details/transaction_details_
|
||||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
|
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
|
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
|
import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
|
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
import 'package:cake_wallet/store/app_store.dart';
|
||||||
import 'package:cake_wallet/store/authentication_store.dart';
|
import 'package:cake_wallet/store/authentication_store.dart';
|
||||||
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
||||||
|
@ -587,7 +588,7 @@ Future<void> setup({
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// wallet is already loaded:
|
// wallet is already loaded:
|
||||||
if (appStore.wallet != null) {
|
if (appStore.wallet != null || requireHardwareWalletConnection()) {
|
||||||
// goes to the dashboard:
|
// goes to the dashboard:
|
||||||
authStore.allowed();
|
authStore.allowed();
|
||||||
// trigger any deep links:
|
// trigger any deep links:
|
||||||
|
@ -781,9 +782,11 @@ Future<void> setup({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getIt.registerFactory(() => WalletListPage(
|
getIt.registerFactoryParam<WalletListPage, Function(BuildContext)?, void>(
|
||||||
|
(Function(BuildContext)? onWalletLoaded, _) => WalletListPage(
|
||||||
walletListViewModel: getIt.get<WalletListViewModel>(),
|
walletListViewModel: getIt.get<WalletListViewModel>(),
|
||||||
authService: getIt.get<AuthService>(),
|
authService: getIt.get<AuthService>(),
|
||||||
|
onWalletLoaded: onWalletLoaded,
|
||||||
));
|
));
|
||||||
|
|
||||||
getIt.registerFactoryParam<WalletEditViewModel, WalletListViewModel, void>(
|
getIt.registerFactoryParam<WalletEditViewModel, WalletListViewModel, void>(
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
||||||
|
import 'package:cake_wallet/di.dart';
|
||||||
|
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
bool requireHardwareWalletConnection() {
|
||||||
|
final name = getIt
|
||||||
|
.get<SharedPreferences>()
|
||||||
|
.getString(PreferencesKey.currentWalletName);
|
||||||
|
final typeRaw =
|
||||||
|
getIt.get<SharedPreferences>().getInt(PreferencesKey.currentWalletType);
|
||||||
|
|
||||||
|
if (typeRaw == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name == null) {
|
||||||
|
throw Exception('Incorrect current wallet name: $name');
|
||||||
|
}
|
||||||
|
|
||||||
|
final type = deserializeFromInt(typeRaw);
|
||||||
|
final walletLoadingService = getIt.get<WalletLoadingService>();
|
||||||
|
return walletLoadingService.requireHardwareWalletConnection(type, name);
|
||||||
|
}
|
|
@ -225,6 +225,19 @@ class CWMonero extends Monero {
|
||||||
language: language,
|
language: language,
|
||||||
height: height);
|
height: height);
|
||||||
|
|
||||||
|
@override
|
||||||
|
WalletCredentials createMoneroRestoreWalletFromHardwareCredentials({
|
||||||
|
required String name,
|
||||||
|
required String password,
|
||||||
|
required int height,
|
||||||
|
required ledger.LedgerConnection ledgerConnection,
|
||||||
|
}) =>
|
||||||
|
MoneroRestoreWalletFromHardwareCredentials(
|
||||||
|
name: name,
|
||||||
|
password: password,
|
||||||
|
height: height,
|
||||||
|
ledgerConnection: ledgerConnection);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createMoneroRestoreWalletFromSeedCredentials(
|
WalletCredentials createMoneroRestoreWalletFromSeedCredentials(
|
||||||
{required String name,
|
{required String name,
|
||||||
|
@ -383,6 +396,18 @@ class CWMonero extends Monero {
|
||||||
checkIfMoneroCIsFine();
|
checkIfMoneroCIsFine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setLedgerConnection(Object wallet, ledger.LedgerConnection connection) {
|
||||||
|
final moneroWallet = wallet as MoneroWallet;
|
||||||
|
moneroWallet.setLedgerConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setGlobalLedgerConnection(ledger.LedgerConnection connection) {
|
||||||
|
gLedger = connection;
|
||||||
|
keepAlive(connection);
|
||||||
|
}
|
||||||
|
|
||||||
bool isViewOnly() {
|
bool isViewOnly() {
|
||||||
return isViewOnlyBySpendKey();
|
return isViewOnlyBySpendKey();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,28 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
|
||||||
|
import 'package:cake_wallet/di.dart';
|
||||||
|
import 'package:cake_wallet/entities/hardware_wallet/require_hardware_wallet_connection.dart';
|
||||||
|
import 'package:cake_wallet/entities/load_current_wallet.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||||
|
import 'package:cake_wallet/store/authentication_store.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
|
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||||
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cake_wallet/entities/load_current_wallet.dart';
|
|
||||||
import 'package:cake_wallet/store/authentication_store.dart';
|
|
||||||
import 'package:rxdart/subjects.dart';
|
import 'package:rxdart/subjects.dart';
|
||||||
|
|
||||||
ReactionDisposer? _onAuthenticationStateChange;
|
ReactionDisposer? _onAuthenticationStateChange;
|
||||||
|
|
||||||
dynamic loginError;
|
dynamic loginError;
|
||||||
StreamController<dynamic> authenticatedErrorStreamController = BehaviorSubject<dynamic>();
|
StreamController<dynamic> authenticatedErrorStreamController =
|
||||||
|
BehaviorSubject<dynamic>();
|
||||||
|
|
||||||
void startAuthenticationStateChange(
|
void startAuthenticationStateChange(
|
||||||
AuthenticationStore authenticationStore,
|
AuthenticationStore authenticationStore,
|
||||||
|
@ -27,18 +37,49 @@ void startAuthenticationStateChange(
|
||||||
_onAuthenticationStateChange ??= autorun((_) async {
|
_onAuthenticationStateChange ??= autorun((_) async {
|
||||||
final state = authenticationStore.state;
|
final state = authenticationStore.state;
|
||||||
|
|
||||||
if (state == AuthenticationState.installed && !SettingsStoreBase.walletPasswordDirectInput) {
|
if (state == AuthenticationState.installed &&
|
||||||
|
!SettingsStoreBase.walletPasswordDirectInput) {
|
||||||
try {
|
try {
|
||||||
await loadCurrentWallet();
|
if (!requireHardwareWalletConnection()) await loadCurrentWallet();
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
loginError = error;
|
loginError = error;
|
||||||
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
|
ExceptionHandler.onError(
|
||||||
|
FlutterErrorDetails(exception: error, stack: stack));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == AuthenticationState.allowed) {
|
if (state == AuthenticationState.allowed) {
|
||||||
await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
|
if (requireHardwareWalletConnection()) {
|
||||||
|
await navigatorKey.currentState!.pushNamedAndRemoveUntil(
|
||||||
|
Routes.connectDevices,
|
||||||
|
(route) => false,
|
||||||
|
arguments: ConnectDevicePageParams(
|
||||||
|
walletType: WalletType.monero,
|
||||||
|
onConnectDevice: (context, ledgerVM) async {
|
||||||
|
monero!.setGlobalLedgerConnection(ledgerVM.connection);
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) => AlertWithOneAction(
|
||||||
|
alertTitle: S.of(context).proceed_on_device,
|
||||||
|
alertContent: S.of(context).proceed_on_device_description,
|
||||||
|
buttonText: S.of(context).cancel,
|
||||||
|
buttonAction: () => Navigator.of(context).pop()),
|
||||||
|
);
|
||||||
|
await loadCurrentWallet();
|
||||||
|
getIt.get<BottomSheetService>().resetCurrentSheet();
|
||||||
|
await navigatorKey.currentState!
|
||||||
|
.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
|
||||||
|
},
|
||||||
|
allowChangeWallet: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.connectDevices, (route) => false, arguments: ConnectDevicePageParams(walletType: walletType, onConnectDevice: onConnectDevice));
|
||||||
|
} else {
|
||||||
|
await navigatorKey.currentState!
|
||||||
|
.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
|
||||||
|
}
|
||||||
if (!(await authenticatedErrorStreamController.stream.isEmpty)) {
|
if (!(await authenticatedErrorStreamController.stream.isEmpty)) {
|
||||||
ExceptionHandler.showError(
|
ExceptionHandler.showError(
|
||||||
(await authenticatedErrorStreamController.stream.first).toString());
|
(await authenticatedErrorStreamController.stream.first).toString());
|
||||||
|
|
|
@ -24,6 +24,7 @@ import 'package:cake_wallet/src/screens/buy/webview_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/cake_pay/auth/cake_pay_account_page.dart';
|
import 'package:cake_wallet/src/screens/cake_pay/auth/cake_pay_account_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/cake_pay/cake_pay.dart';
|
import 'package:cake_wallet/src/screens/cake_pay/cake_pay.dart';
|
||||||
import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart';
|
import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/connect_device/monero_hardware_wallet_options_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/connect_device/select_hardware_wallet_account_page.dart';
|
import 'package:cake_wallet/src/screens/connect_device/select_hardware_wallet_account_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/contact/contact_list_page.dart';
|
import 'package:cake_wallet/src/screens/contact/contact_list_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/contact/contact_page.dart';
|
import 'package:cake_wallet/src/screens/contact/contact_page.dart';
|
||||||
|
@ -212,6 +213,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
final type = arguments[0] as WalletType;
|
final type = arguments[0] as WalletType;
|
||||||
final walletVM = getIt.get<WalletHardwareRestoreViewModel>(param1: type);
|
final walletVM = getIt.get<WalletHardwareRestoreViewModel>(param1: type);
|
||||||
|
|
||||||
|
if (type == WalletType.monero)
|
||||||
|
return CupertinoPageRoute<void>(builder: (_) => MoneroHardwareWalletOptionsPage(walletVM));
|
||||||
|
|
||||||
return CupertinoPageRoute<void>(builder: (_) => SelectHardwareWalletAccountPage(walletVM));
|
return CupertinoPageRoute<void>(builder: (_) => SelectHardwareWalletAccountPage(walletVM));
|
||||||
|
|
||||||
case Routes.setupPin:
|
case Routes.setupPin:
|
||||||
|
@ -403,8 +407,11 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<NanoChangeRepPage>());
|
return CupertinoPageRoute<void>(builder: (_) => getIt.get<NanoChangeRepPage>());
|
||||||
|
|
||||||
case Routes.walletList:
|
case Routes.walletList:
|
||||||
|
final onWalletLoaded = settings.arguments as Function(BuildContext)?;
|
||||||
return MaterialPageRoute<void>(
|
return MaterialPageRoute<void>(
|
||||||
fullscreenDialog: true, builder: (_) => getIt.get<WalletListPage>());
|
fullscreenDialog: true,
|
||||||
|
builder: (_) => getIt.get<WalletListPage>(param1: onWalletLoaded),
|
||||||
|
);
|
||||||
|
|
||||||
case Routes.walletEdit:
|
case Routes.walletEdit:
|
||||||
return MaterialPageRoute<void>(
|
return MaterialPageRoute<void>(
|
||||||
|
|
|
@ -2,9 +2,12 @@ import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/connect_device/widgets/device_tile.dart';
|
import 'package:cake_wallet/src/screens/connect_device/widgets/device_tile.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
|
||||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
@ -17,35 +20,46 @@ typedef OnConnectDevice = void Function(BuildContext, LedgerViewModel);
|
||||||
class ConnectDevicePageParams {
|
class ConnectDevicePageParams {
|
||||||
final WalletType walletType;
|
final WalletType walletType;
|
||||||
final OnConnectDevice onConnectDevice;
|
final OnConnectDevice onConnectDevice;
|
||||||
|
final bool allowChangeWallet;
|
||||||
|
|
||||||
ConnectDevicePageParams(
|
ConnectDevicePageParams({
|
||||||
{required this.walletType, required this.onConnectDevice});
|
required this.walletType,
|
||||||
|
required this.onConnectDevice,
|
||||||
|
this.allowChangeWallet = false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConnectDevicePage extends BasePage {
|
class ConnectDevicePage extends BasePage {
|
||||||
final WalletType walletType;
|
final WalletType walletType;
|
||||||
final OnConnectDevice onConnectDevice;
|
final OnConnectDevice onConnectDevice;
|
||||||
|
final bool allowChangeWallet;
|
||||||
final LedgerViewModel ledgerVM;
|
final LedgerViewModel ledgerVM;
|
||||||
|
|
||||||
ConnectDevicePage(ConnectDevicePageParams params, this.ledgerVM)
|
ConnectDevicePage(ConnectDevicePageParams params, this.ledgerVM)
|
||||||
: walletType = params.walletType,
|
: walletType = params.walletType,
|
||||||
onConnectDevice = params.onConnectDevice;
|
onConnectDevice = params.onConnectDevice,
|
||||||
|
allowChangeWallet = params.allowChangeWallet;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get title => S.current.restore_title_from_hardware_wallet;
|
String get title => S.current.restore_title_from_hardware_wallet;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) =>
|
Widget body(BuildContext context) => ConnectDevicePageBody(
|
||||||
ConnectDevicePageBody(walletType, onConnectDevice, ledgerVM);
|
walletType, onConnectDevice, allowChangeWallet, ledgerVM);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConnectDevicePageBody extends StatefulWidget {
|
class ConnectDevicePageBody extends StatefulWidget {
|
||||||
final WalletType walletType;
|
final WalletType walletType;
|
||||||
final OnConnectDevice onConnectDevice;
|
final OnConnectDevice onConnectDevice;
|
||||||
|
final bool allowChangeWallet;
|
||||||
final LedgerViewModel ledgerVM;
|
final LedgerViewModel ledgerVM;
|
||||||
|
|
||||||
const ConnectDevicePageBody(
|
const ConnectDevicePageBody(
|
||||||
this.walletType, this.onConnectDevice, this.ledgerVM);
|
this.walletType,
|
||||||
|
this.onConnectDevice,
|
||||||
|
this.allowChangeWallet,
|
||||||
|
this.ledgerVM,
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ConnectDevicePageBodyState createState() => ConnectDevicePageBodyState();
|
ConnectDevicePageBodyState createState() => ConnectDevicePageBodyState();
|
||||||
|
@ -102,6 +116,7 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
|
|
||||||
Future<void> _refreshBleDevices() async {
|
Future<void> _refreshBleDevices() async {
|
||||||
try {
|
try {
|
||||||
|
if (widget.ledgerVM.bleIsEnabled) {
|
||||||
_bleRefresh = widget.ledgerVM
|
_bleRefresh = widget.ledgerVM
|
||||||
.scanForBleDevices()
|
.scanForBleDevices()
|
||||||
.listen((device) => setState(() => bleDevices.add(device)))
|
.listen((device) => setState(() => bleDevices.add(device)))
|
||||||
|
@ -110,6 +125,7 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
});
|
});
|
||||||
_bleRefreshTimer?.cancel();
|
_bleRefreshTimer?.cancel();
|
||||||
_bleRefreshTimer = null;
|
_bleRefreshTimer = null;
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
}
|
}
|
||||||
|
@ -227,9 +243,7 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||||
.extension<CakeTextTheme>()!
|
|
||||||
.titleColor,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -247,11 +261,27 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
]
|
],
|
||||||
|
if (widget.allowChangeWallet) ...[
|
||||||
|
PrimaryButton(
|
||||||
|
text: S.of(context).wallets,
|
||||||
|
color: Theme.of(context).extension<WalletListTheme>()!.createNewWalletButtonBackgroundColor,
|
||||||
|
textColor: Theme.of(context).extension<WalletListTheme>()!.restoreWalletButtonTextColor,
|
||||||
|
onPressed: _onChangeWallet,
|
||||||
|
)
|
||||||
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onChangeWallet() {
|
||||||
|
Navigator.of(context).pushNamed(
|
||||||
|
Routes.walletList,
|
||||||
|
arguments: (BuildContext context) => Navigator.of(context)
|
||||||
|
.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,230 @@
|
||||||
|
import 'package:cake_wallet/core/wallet_name_validator.dart';
|
||||||
|
import 'package:cake_wallet/entities/generate_name.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||||
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
|
import 'package:cake_wallet/view_model/wallet_hardware_restore_view_model.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
class MoneroHardwareWalletOptionsPage extends BasePage {
|
||||||
|
MoneroHardwareWalletOptionsPage(this._walletHardwareRestoreVM);
|
||||||
|
|
||||||
|
final WalletHardwareRestoreViewModel _walletHardwareRestoreVM;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => S.current.restore_title_from_hardware_wallet;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget body(BuildContext context) =>
|
||||||
|
_MoneroHardwareWalletOptionsForm(_walletHardwareRestoreVM);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MoneroHardwareWalletOptionsForm extends StatefulWidget {
|
||||||
|
const _MoneroHardwareWalletOptionsForm(this._walletHardwareRestoreVM);
|
||||||
|
|
||||||
|
final WalletHardwareRestoreViewModel _walletHardwareRestoreVM;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_MoneroHardwareWalletOptionsFormState createState() =>
|
||||||
|
_MoneroHardwareWalletOptionsFormState(_walletHardwareRestoreVM);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MoneroHardwareWalletOptionsFormState
|
||||||
|
extends State<_MoneroHardwareWalletOptionsForm> {
|
||||||
|
_MoneroHardwareWalletOptionsFormState(this._walletHardwareRestoreVM)
|
||||||
|
: _formKey = GlobalKey<FormState>(),
|
||||||
|
_blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
|
||||||
|
_blockHeightFocusNode = FocusNode(),
|
||||||
|
_controller = TextEditingController();
|
||||||
|
|
||||||
|
final GlobalKey<FormState> _formKey;
|
||||||
|
final GlobalKey<BlockchainHeightState> _blockchainHeightKey;
|
||||||
|
final FocusNode _blockHeightFocusNode;
|
||||||
|
final WalletHardwareRestoreViewModel _walletHardwareRestoreVM;
|
||||||
|
final TextEditingController _controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_setEffects(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(top: 24),
|
||||||
|
child: ScrollableWithBottomSection(
|
||||||
|
contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||||
|
content: Center(
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 0),
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
children: [
|
||||||
|
TextFormField(
|
||||||
|
onChanged: (value) =>
|
||||||
|
_walletHardwareRestoreVM.name = value,
|
||||||
|
controller: _controller,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20.0,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<CakeTextTheme>()!
|
||||||
|
.titleColor,
|
||||||
|
),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintStyle: TextStyle(
|
||||||
|
fontSize: 18.0,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<NewWalletTheme>()!
|
||||||
|
.hintTextColor,
|
||||||
|
),
|
||||||
|
hintText: S.of(context).wallet_name,
|
||||||
|
focusedBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<NewWalletTheme>()!
|
||||||
|
.underlineColor,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
enabledBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<NewWalletTheme>()!
|
||||||
|
.underlineColor,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
suffixIcon: Semantics(
|
||||||
|
label: S.of(context).generate_name,
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: _onGenerateName,
|
||||||
|
icon: Container(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(6.0),
|
||||||
|
color: Theme.of(context).hintColor,
|
||||||
|
),
|
||||||
|
width: 34,
|
||||||
|
height: 34,
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/refresh_icon.png',
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<SendPageTheme>()!
|
||||||
|
.textFieldButtonIconColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
validator: WalletNameValidator(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 20),
|
||||||
|
child: BlockchainHeightWidget(
|
||||||
|
focusNode: _blockHeightFocusNode,
|
||||||
|
key: _blockchainHeightKey,
|
||||||
|
hasDatePicker: true,
|
||||||
|
walletType: WalletType.monero,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomSectionPadding: EdgeInsets.all(24),
|
||||||
|
bottomSection: Observer(
|
||||||
|
builder: (context) => LoadingPrimaryButton(
|
||||||
|
onPressed: _confirmForm,
|
||||||
|
text: S.of(context).seed_language_next,
|
||||||
|
color: Colors.green,
|
||||||
|
textColor: Colors.white,
|
||||||
|
isDisabled: _walletHardwareRestoreVM.name.isEmpty,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onGenerateName() async {
|
||||||
|
final rName = await generateName();
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_controller.text = rName;
|
||||||
|
_walletHardwareRestoreVM.name = rName;
|
||||||
|
_controller.selection = TextSelection.fromPosition(
|
||||||
|
TextPosition(offset: _controller.text.length));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _confirmForm() async {
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) => AlertWithOneAction(
|
||||||
|
alertTitle: S.of(context).proceed_on_device,
|
||||||
|
alertContent: S.of(context).proceed_on_device_description,
|
||||||
|
buttonText: S.of(context).cancel,
|
||||||
|
buttonAction: () => Navigator.of(context).pop(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final options = {'height': _blockchainHeightKey.currentState?.height ?? -1};
|
||||||
|
await _walletHardwareRestoreVM.create(options: options);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _effectsInstalled = false;
|
||||||
|
|
||||||
|
void _setEffects(BuildContext context) {
|
||||||
|
if (_effectsInstalled) return;
|
||||||
|
|
||||||
|
reaction((_) => _walletHardwareRestoreVM.error, (String? error) {
|
||||||
|
if (error != null) {
|
||||||
|
if (error == S.current.ledger_connection_error)
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) => AlertWithOneAction(
|
||||||
|
alertTitle: S.of(context).error,
|
||||||
|
alertContent: error,
|
||||||
|
buttonText: S.of(context).ok,
|
||||||
|
buttonAction: () {
|
||||||
|
_walletHardwareRestoreVM.error = null;
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_effectsInstalled = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/filter_theme.dart';
|
||||||
import 'package:cake_wallet/utils/show_bar.dart';
|
import 'package:cake_wallet/utils/show_bar.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
|
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
|
||||||
|
@ -160,25 +161,60 @@ class _ContactPageBodyState extends State<ContactPageBody> with SingleTickerProv
|
||||||
Widget _buildWalletContacts(BuildContext context) {
|
Widget _buildWalletContacts(BuildContext context) {
|
||||||
final walletContacts = widget.contactListViewModel.walletContactsToShow;
|
final walletContacts = widget.contactListViewModel.walletContactsToShow;
|
||||||
|
|
||||||
|
final groupedContacts = <String, List<ContactBase>>{};
|
||||||
|
for (var contact in walletContacts) {
|
||||||
|
final baseName = _extractBaseName(contact.name);
|
||||||
|
groupedContacts.putIfAbsent(baseName, () => []).add(contact);
|
||||||
|
}
|
||||||
|
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
shrinkWrap: true,
|
itemCount: groupedContacts.length * 2,
|
||||||
itemCount: walletContacts.length * 2,
|
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
if (index.isOdd) {
|
if (index.isOdd) {
|
||||||
return StandardListSeparator();
|
return StandardListSeparator();
|
||||||
} else {
|
} else {
|
||||||
final walletInfo = walletContacts[index ~/ 2];
|
final groupIndex = index ~/ 2;
|
||||||
return generateRaw(context, walletInfo);
|
final groupName = groupedContacts.keys.elementAt(groupIndex);
|
||||||
|
final groupContacts = groupedContacts[groupName]!;
|
||||||
|
|
||||||
|
if (groupContacts.length == 1) {
|
||||||
|
final contact = groupContacts[0];
|
||||||
|
return generateRaw(context, contact);
|
||||||
|
} else {
|
||||||
|
final activeContact = groupContacts.firstWhere(
|
||||||
|
(contact) => contact.name.contains('Active'),
|
||||||
|
orElse: () => groupContacts[0],
|
||||||
|
);
|
||||||
|
|
||||||
|
return ExpansionTile(
|
||||||
|
title: Text(
|
||||||
|
groupName,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
leading: _buildCurrencyIcon(activeContact),
|
||||||
|
tilePadding: EdgeInsets.zero,
|
||||||
|
childrenPadding: const EdgeInsets.only(left: 16),
|
||||||
|
expandedCrossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
expandedAlignment: Alignment.topLeft,
|
||||||
|
children: groupContacts.map((contact) => generateRaw(context, contact)).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _extractBaseName(String name) {
|
||||||
|
final bracketIndex = name.indexOf('(');
|
||||||
|
return (bracketIndex != -1) ? name.substring(0, bracketIndex).trim() : name;
|
||||||
|
}
|
||||||
|
|
||||||
Widget generateRaw(BuildContext context, ContactBase contact) {
|
Widget generateRaw(BuildContext context, ContactBase contact) {
|
||||||
final image = contact.type.iconPath;
|
final currencyIcon = _buildCurrencyIcon(contact);
|
||||||
final currencyIcon = image != null
|
|
||||||
? Image.asset(image, height: 24, width: 24)
|
|
||||||
: const SizedBox(height: 24, width: 24);
|
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
|
@ -219,6 +255,13 @@ class _ContactPageBodyState extends State<ContactPageBody> with SingleTickerProv
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildCurrencyIcon(ContactBase contact) {
|
||||||
|
final image = contact.type.iconPath;
|
||||||
|
return image != null
|
||||||
|
? Image.asset(image, height: 24, width: 24)
|
||||||
|
: const SizedBox(height: 24, width: 24);
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> showNameAndAddressDialog(BuildContext context, String name, String address) async {
|
Future<bool> showNameAndAddressDialog(BuildContext context, String name, String address) async {
|
||||||
return await showPopUp<bool>(
|
return await showPopUp<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -263,12 +306,13 @@ class _ContactListBodyState extends State<ContactListBody> {
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
widget.tabController.removeListener(_handleTabChange);
|
widget.tabController.removeListener(_handleTabChange);
|
||||||
|
widget.contactListViewModel.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final contacts = widget.contactListViewModel.contacts;
|
final contacts = widget.contactListViewModel.contactsToShow;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Container(
|
body: Container(
|
||||||
child: FilteredList(
|
child: FilteredList(
|
||||||
|
|
|
@ -1,44 +1,56 @@
|
||||||
|
import 'package:another_flushbar/flushbar.dart';
|
||||||
|
import 'package:cake_wallet/core/auth_service.dart';
|
||||||
import 'package:cake_wallet/core/new_wallet_arguments.dart';
|
import 'package:cake_wallet/core/new_wallet_arguments.dart';
|
||||||
import 'package:cake_wallet/entities/wallet_edit_page_arguments.dart';
|
import 'package:cake_wallet/entities/wallet_edit_page_arguments.dart';
|
||||||
import 'package:cake_wallet/entities/wallet_list_order_types.dart';
|
import 'package:cake_wallet/entities/wallet_list_order_types.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
|
import 'package:cake_wallet/routes.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_list_widget.dart';
|
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_list_widget.dart';
|
||||||
import 'package:cake_wallet/src/screens/new_wallet/widgets/grouped_wallet_expansion_tile.dart';
|
import 'package:cake_wallet/src/screens/new_wallet/widgets/grouped_wallet_expansion_tile.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_list/edit_wallet_button_widget.dart';
|
import 'package:cake_wallet/src/screens/wallet_list/edit_wallet_button_widget.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_list/filtered_list.dart';
|
import 'package:cake_wallet/src/screens/wallet_list/filtered_list.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
|
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
|
||||||
import 'package:cake_wallet/core/auth_service.dart';
|
|
||||||
import 'package:cake_wallet/themes/extensions/filter_theme.dart';
|
import 'package:cake_wallet/themes/extensions/filter_theme.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
|
import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
|
||||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
import 'package:cake_wallet/utils/show_bar.dart';
|
import 'package:cake_wallet/utils/show_bar.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
||||||
import 'package:another_flushbar/flushbar.dart';
|
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
|
||||||
|
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
|
||||||
import 'package:cw_core/wallet_type.dart';
|
|
||||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
|
||||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
|
||||||
|
|
||||||
class WalletListPage extends BasePage {
|
class WalletListPage extends BasePage {
|
||||||
WalletListPage({required this.walletListViewModel, required this.authService});
|
WalletListPage({
|
||||||
|
required this.walletListViewModel,
|
||||||
|
required this.authService,
|
||||||
|
this.onWalletLoaded,
|
||||||
|
});
|
||||||
|
|
||||||
final WalletListViewModel walletListViewModel;
|
final WalletListViewModel walletListViewModel;
|
||||||
final AuthService authService;
|
final AuthService authService;
|
||||||
|
final Function(BuildContext)? onWalletLoaded;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get title => S.current.wallets;
|
String get title => S.current.wallets;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) =>
|
Widget body(BuildContext context) => WalletListBody(
|
||||||
WalletListBody(walletListViewModel: walletListViewModel, authService: authService);
|
walletListViewModel: walletListViewModel,
|
||||||
|
authService: authService,
|
||||||
|
onWalletLoaded:
|
||||||
|
onWalletLoaded ?? (context) => Navigator.of(context).pop(),
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget trailing(BuildContext context) {
|
Widget trailing(BuildContext context) {
|
||||||
|
@ -89,10 +101,15 @@ class WalletListPage extends BasePage {
|
||||||
}
|
}
|
||||||
|
|
||||||
class WalletListBody extends StatefulWidget {
|
class WalletListBody extends StatefulWidget {
|
||||||
WalletListBody({required this.walletListViewModel, required this.authService});
|
WalletListBody({
|
||||||
|
required this.walletListViewModel,
|
||||||
|
required this.authService,
|
||||||
|
required this.onWalletLoaded,
|
||||||
|
});
|
||||||
|
|
||||||
final WalletListViewModel walletListViewModel;
|
final WalletListViewModel walletListViewModel;
|
||||||
final AuthService authService;
|
final AuthService authService;
|
||||||
|
final Function(BuildContext) onWalletLoaded;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletListBodyState createState() => WalletListBodyState();
|
WalletListBodyState createState() => WalletListBodyState();
|
||||||
|
@ -119,8 +136,8 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final newWalletImage =
|
final newWalletImage = Image.asset('assets/images/new_wallet.png',
|
||||||
Image.asset('assets/images/new_wallet.png', height: 12, width: 12, color: Colors.white);
|
height: 12, width: 12, color: Colors.white);
|
||||||
final restoreWalletImage = Image.asset('assets/images/restore_wallet.png',
|
final restoreWalletImage = Image.asset('assets/images/restore_wallet.png',
|
||||||
height: 12,
|
height: 12,
|
||||||
width: 12,
|
width: 12,
|
||||||
|
@ -181,8 +198,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
trailingWidget: EditWalletButtonWidget(
|
trailingWidget: EditWalletButtonWidget(
|
||||||
width: 74,
|
width: 74,
|
||||||
isGroup: true,
|
isGroup: true,
|
||||||
isExpanded:
|
isExpanded: widget.walletListViewModel.expansionTileStateTrack[index]!,
|
||||||
widget.walletListViewModel.expansionTileStateTrack[index]!,
|
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final wallet = widget.walletListViewModel
|
final wallet = widget.walletListViewModel
|
||||||
.convertWalletInfoToWalletListItem(group.wallets.first);
|
.convertWalletInfoToWalletListItem(group.wallets.first);
|
||||||
|
@ -199,8 +215,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
childWallets: group.wallets.map((walletInfo) {
|
childWallets: group.wallets.map((walletInfo) {
|
||||||
return widget.walletListViewModel
|
return widget.walletListViewModel.convertWalletInfoToWalletListItem(walletInfo);
|
||||||
.convertWalletInfoToWalletListItem(walletInfo);
|
|
||||||
}).toList(),
|
}).toList(),
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
onChildItemTapped: (wallet) =>
|
onChildItemTapped: (wallet) =>
|
||||||
|
@ -330,8 +345,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
arguments: NewWalletArguments(
|
arguments: NewWalletArguments(
|
||||||
type: widget.walletListViewModel.currentWalletType,
|
type: widget.walletListViewModel.currentWalletType,
|
||||||
),
|
),
|
||||||
conditionToDetermineIfToUse2FA:
|
conditionToDetermineIfToUse2FA: widget.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets,
|
||||||
widget.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
Navigator.of(context).pushNamed(
|
Navigator.of(context).pushNamed(
|
||||||
|
@ -346,8 +360,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
widget.authService.authenticateAction(
|
widget.authService.authenticateAction(
|
||||||
context,
|
context,
|
||||||
route: Routes.newWalletType,
|
route: Routes.newWalletType,
|
||||||
conditionToDetermineIfToUse2FA:
|
conditionToDetermineIfToUse2FA: widget.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets,
|
||||||
widget.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
Navigator.of(context).pushNamed(Routes.newWalletType);
|
Navigator.of(context).pushNamed(Routes.newWalletType);
|
||||||
|
@ -368,8 +381,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
context,
|
context,
|
||||||
route: Routes.restoreOptions,
|
route: Routes.restoreOptions,
|
||||||
arguments: false,
|
arguments: false,
|
||||||
conditionToDetermineIfToUse2FA:
|
conditionToDetermineIfToUse2FA: widget.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets,
|
||||||
widget.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
Navigator.of(context).pushNamed(Routes.restoreOptions, arguments: false);
|
Navigator.of(context).pushNamed(Routes.restoreOptions, arguments: false);
|
||||||
|
@ -441,12 +453,36 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
await widget.authService.authenticateAction(
|
await widget.authService.authenticateAction(
|
||||||
context,
|
context,
|
||||||
onAuthSuccess: (isAuthenticatedSuccessfully) async {
|
onAuthSuccess: (isAuthenticatedSuccessfully) async {
|
||||||
if (!isAuthenticatedSuccessfully) {
|
if (!isAuthenticatedSuccessfully) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name));
|
if (widget.walletListViewModel
|
||||||
|
.requireHardwareWalletConnection(wallet)) {
|
||||||
|
await Navigator.of(context).pushNamed(
|
||||||
|
Routes.connectDevices,
|
||||||
|
arguments: ConnectDevicePageParams(
|
||||||
|
walletType: WalletType.monero,
|
||||||
|
onConnectDevice: (context, ledgerVM) async {
|
||||||
|
monero!.setGlobalLedgerConnection(ledgerVM.connection);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) => AlertWithOneAction(
|
||||||
|
alertTitle: S.of(context).proceed_on_device,
|
||||||
|
alertContent: S.of(context).proceed_on_device_description,
|
||||||
|
buttonText: S.of(context).cancel,
|
||||||
|
buttonAction: () => Navigator.of(context).pop()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
changeProcessText(
|
||||||
|
S.of(context).wallet_list_loading_wallet(wallet.name));
|
||||||
await widget.walletListViewModel.loadWallet(wallet);
|
await widget.walletListViewModel.loadWallet(wallet);
|
||||||
await hideProgressText();
|
await hideProgressText();
|
||||||
// only pop the wallets route in mobile as it will go back to dashboard page
|
// only pop the wallets route in mobile as it will go back to dashboard page
|
||||||
|
@ -454,13 +490,15 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
if (responsiveLayoutUtil.shouldRenderMobileUI) {
|
if (responsiveLayoutUtil.shouldRenderMobileUI) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (this.mounted) {
|
if (this.mounted) {
|
||||||
Navigator.of(context).pop();
|
widget.onWalletLoaded.call(context);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (this.mounted) {
|
if (this.mounted) {
|
||||||
changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
|
changeProcessText(S
|
||||||
|
.of(context)
|
||||||
|
.wallet_list_failed_to_load(wallet.name, e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -28,7 +28,8 @@ abstract class ContactListViewModelBase with Store {
|
||||||
isAutoGenerateEnabled =
|
isAutoGenerateEnabled =
|
||||||
settingsStore.autoGenerateSubaddressStatus == AutoGenerateSubaddressStatus.enabled {
|
settingsStore.autoGenerateSubaddressStatus == AutoGenerateSubaddressStatus.enabled {
|
||||||
walletInfoSource.values.forEach((info) {
|
walletInfoSource.values.forEach((info) {
|
||||||
if ([WalletType.monero, WalletType.wownero, WalletType.haven].contains(info.type) && info.addressInfos != null) {
|
if ([WalletType.monero, WalletType.wownero, WalletType.haven].contains(info.type) &&
|
||||||
|
info.addressInfos != null) {
|
||||||
for (var key in info.addressInfos!.keys) {
|
for (var key in info.addressInfos!.keys) {
|
||||||
final value = info.addressInfos![key];
|
final value = info.addressInfos![key];
|
||||||
final address = value?.first;
|
final address = value?.first;
|
||||||
|
@ -60,15 +61,19 @@ abstract class ContactListViewModelBase with Store {
|
||||||
address,
|
address,
|
||||||
name,
|
name,
|
||||||
walletTypeToCryptoCurrency(info.type,
|
walletTypeToCryptoCurrency(info.type,
|
||||||
isTestnet:
|
isTestnet: info.network == null
|
||||||
info.network == null ? false : info.network!.toLowerCase().contains("testnet")),
|
? false
|
||||||
|
: info.network!.toLowerCase().contains("testnet")),
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
walletContacts.add(WalletContact(
|
walletContacts.add(WalletContact(
|
||||||
info.address,
|
info.address,
|
||||||
_createName(info.name, "", key: [WalletType.monero, WalletType.wownero, WalletType.haven].contains(info.type) ? 0 : null),
|
_createName(info.name, "",
|
||||||
|
key: [WalletType.monero, WalletType.wownero, WalletType.haven].contains(info.type)
|
||||||
|
? 0
|
||||||
|
: null),
|
||||||
walletTypeToCryptoCurrency(info.type),
|
walletTypeToCryptoCurrency(info.type),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -82,8 +87,11 @@ abstract class ContactListViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
String _createName(String walletName, String label, {int? key = null}) {
|
String _createName(String walletName, String label, {int? key = null}) {
|
||||||
final actualLabel = label.replaceAll(RegExp(r'active', caseSensitive: false), S.current.active).replaceAll(RegExp(r'silent payments', caseSensitive: false), S.current.silent_payments);
|
final actualLabel = label
|
||||||
return '$walletName${key == null ? "" : " [#${key}]"} ${actualLabel.isNotEmpty ? "($actualLabel)" : ""}'.trim();
|
.replaceAll(RegExp(r'active', caseSensitive: false), S.current.active)
|
||||||
|
.replaceAll(RegExp(r'silent payments', caseSensitive: false), S.current.silent_payments);
|
||||||
|
return '$walletName${key == null ? "" : " [#${key}]"} ${actualLabel.isNotEmpty ? "($actualLabel)" : ""}'
|
||||||
|
.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
final bool isAutoGenerateEnabled;
|
final bool isAutoGenerateEnabled;
|
||||||
|
@ -108,18 +116,19 @@ abstract class ContactListViewModelBase with Store {
|
||||||
Future<void> delete(ContactRecord contact) async => contact.original.delete();
|
Future<void> delete(ContactRecord contact) async => contact.original.delete();
|
||||||
|
|
||||||
ObservableList<ContactRecord> get contactsToShow =>
|
ObservableList<ContactRecord> get contactsToShow =>
|
||||||
ObservableList.of(contacts.where((element) => _isValidForCurrency(element)));
|
ObservableList.of(contacts.where((element) => _isValidForCurrency(element, false)));
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
List<WalletContact> get walletContactsToShow =>
|
List<WalletContact> get walletContactsToShow =>
|
||||||
walletContacts.where((element) => _isValidForCurrency(element)).toList();
|
walletContacts.where((element) => _isValidForCurrency(element, true)).toList();
|
||||||
|
|
||||||
bool _isValidForCurrency(ContactBase element) {
|
bool _isValidForCurrency(ContactBase element, bool isWalletContact) {
|
||||||
if (element.name.contains('Silent Payments')) return false;
|
if (_currency == null) return true;
|
||||||
if (element.name.contains('MWEB')) return false;
|
if (!element.name.contains('Active') &&
|
||||||
|
isWalletContact &&
|
||||||
|
(element.type == CryptoCurrency.btc || element.type == CryptoCurrency.ltc)) return false;
|
||||||
|
|
||||||
return _currency == null ||
|
return element.type == _currency ||
|
||||||
element.type == _currency ||
|
|
||||||
(element.type.tag != null &&
|
(element.type.tag != null &&
|
||||||
_currency?.tag != null &&
|
_currency?.tag != null &&
|
||||||
element.type.tag == _currency?.tag) ||
|
element.type.tag == _currency?.tag) ||
|
||||||
|
|
|
@ -428,7 +428,7 @@ abstract class DashboardViewModelBase with Store {
|
||||||
// to not cause work duplication, this will do the job as well, it will be slightly less precise
|
// to not cause work duplication, this will do the job as well, it will be slightly less precise
|
||||||
// about what happened - but still enough.
|
// about what happened - but still enough.
|
||||||
// if (keys['privateSpendKey'] == List.generate(64, (index) => "0").join("")) "Private spend key is 0",
|
// if (keys['privateSpendKey'] == List.generate(64, (index) => "0").join("")) "Private spend key is 0",
|
||||||
if (keys['privateViewKey'] == List.generate(64, (index) => "0").join(""))
|
if (keys['privateViewKey'] == List.generate(64, (index) => "0").join("") && !wallet.isHardwareWallet)
|
||||||
"private view key is 0",
|
"private view key is 0",
|
||||||
// if (keys['publicSpendKey'] == List.generate(64, (index) => "0").join("")) "public spend key is 0",
|
// if (keys['publicSpendKey'] == List.generate(64, (index) => "0").join("")) "public spend key is 0",
|
||||||
if (keys['publicViewKey'] == List.generate(64, (index) => "0").join(""))
|
if (keys['publicViewKey'] == List.generate(64, (index) => "0").join(""))
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:io';
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
import 'package:cake_wallet/polygon/polygon.dart';
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/utils/device_info.dart';
|
import 'package:cake_wallet/utils/device_info.dart';
|
||||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||||
|
@ -114,6 +115,8 @@ abstract class LedgerViewModelBase with Store {
|
||||||
|
|
||||||
void setLedger(WalletBase wallet) {
|
void setLedger(WalletBase wallet) {
|
||||||
switch (wallet.type) {
|
switch (wallet.type) {
|
||||||
|
case WalletType.monero:
|
||||||
|
return monero!.setLedgerConnection(wallet, connection);
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
return bitcoin!.setLedgerConnection(wallet, connection);
|
return bitcoin!.setLedgerConnection(wallet, connection);
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
|
import 'package:cake_wallet/core/generate_wallet_password.dart';
|
||||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
import 'package:cake_wallet/polygon/polygon.dart';
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
import 'package:cake_wallet/store/app_store.dart';
|
||||||
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
||||||
|
@ -104,6 +106,15 @@ abstract class WalletHardwareRestoreViewModelBase extends WalletCreationVM with
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
credentials = polygon!.createPolygonHardwareWalletCredentials(name: name, hwAccountData: selectedAccount!);
|
credentials = polygon!.createPolygonHardwareWalletCredentials(name: name, hwAccountData: selectedAccount!);
|
||||||
break;
|
break;
|
||||||
|
case WalletType.monero:
|
||||||
|
final password = walletPassword ?? generateWalletPassword();
|
||||||
|
|
||||||
|
credentials = monero!.createMoneroRestoreWalletFromHardwareCredentials(
|
||||||
|
name: name,
|
||||||
|
ledgerConnection: ledgerViewModel.connection,
|
||||||
|
password: password,
|
||||||
|
height: _options['height'] as int? ?? 0,
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected type: ${type.toString()}');
|
throw Exception('Unexpected type: ${type.toString()}');
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,10 @@ abstract class WalletListViewModelBase with Store {
|
||||||
|
|
||||||
WalletType get currentWalletType => _appStore.wallet!.type;
|
WalletType get currentWalletType => _appStore.wallet!.type;
|
||||||
|
|
||||||
|
bool requireHardwareWalletConnection(WalletListItem walletItem) =>
|
||||||
|
_walletLoadingService.requireHardwareWalletConnection(
|
||||||
|
walletItem.type, walletItem.name);
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> loadWallet(WalletListItem walletItem) async {
|
Future<void> loadWallet(WalletListItem walletItem) async {
|
||||||
// bool switchingToSameWalletType = walletItem.type == _appStore.wallet?.type;
|
// bool switchingToSameWalletType = walletItem.type == _appStore.wallet?.type;
|
||||||
|
@ -87,7 +91,8 @@ abstract class WalletListViewModelBase with Store {
|
||||||
singleWalletsList.clear();
|
singleWalletsList.clear();
|
||||||
|
|
||||||
wallets.addAll(
|
wallets.addAll(
|
||||||
_walletInfoSource.values.map((info) => convertWalletInfoToWalletListItem(info)),
|
_walletInfoSource.values
|
||||||
|
.map((info) => convertWalletInfoToWalletListItem(info)),
|
||||||
);
|
);
|
||||||
|
|
||||||
//========== Split into shared seed groups and single wallets list
|
//========== Split into shared seed groups and single wallets list
|
||||||
|
@ -95,7 +100,8 @@ abstract class WalletListViewModelBase with Store {
|
||||||
|
|
||||||
for (var group in _walletManager.walletGroups) {
|
for (var group in _walletManager.walletGroups) {
|
||||||
if (group.wallets.length == 1) {
|
if (group.wallets.length == 1) {
|
||||||
singleWalletsList.add(convertWalletInfoToWalletListItem(group.wallets.first));
|
singleWalletsList
|
||||||
|
.add(convertWalletInfoToWalletListItem(group.wallets.first));
|
||||||
} else {
|
} else {
|
||||||
multiWalletGroups.add(group);
|
multiWalletGroups.add(group);
|
||||||
}
|
}
|
||||||
|
@ -148,9 +154,11 @@ abstract class WalletListViewModelBase with Store {
|
||||||
List<WalletInfo> walletInfoSourceCopy = _walletInfoSource.values.toList();
|
List<WalletInfo> walletInfoSourceCopy = _walletInfoSource.values.toList();
|
||||||
await _walletInfoSource.clear();
|
await _walletInfoSource.clear();
|
||||||
if (ascending) {
|
if (ascending) {
|
||||||
walletInfoSourceCopy.sort((a, b) => a.type.toString().compareTo(b.type.toString()));
|
walletInfoSourceCopy
|
||||||
|
.sort((a, b) => a.type.toString().compareTo(b.type.toString()));
|
||||||
} else {
|
} else {
|
||||||
walletInfoSourceCopy.sort((a, b) => b.type.toString().compareTo(a.type.toString()));
|
walletInfoSourceCopy
|
||||||
|
.sort((a, b) => b.type.toString().compareTo(a.type.toString()));
|
||||||
}
|
}
|
||||||
await _walletInfoSource.addAll(walletInfoSourceCopy);
|
await _walletInfoSource.addAll(walletInfoSourceCopy);
|
||||||
updateList();
|
updateList();
|
||||||
|
@ -213,7 +221,8 @@ abstract class WalletListViewModelBase with Store {
|
||||||
name: info.name,
|
name: info.name,
|
||||||
type: info.type,
|
type: info.type,
|
||||||
key: info.key,
|
key: info.key,
|
||||||
isCurrent: info.name == _appStore.wallet?.name && info.type == _appStore.wallet?.type,
|
isCurrent: info.name == _appStore.wallet?.name &&
|
||||||
|
info.type == _appStore.wallet?.type,
|
||||||
isEnabled: availableWalletTypes.contains(info.type),
|
isEnabled: availableWalletTypes.contains(info.type),
|
||||||
isTestnet: info.network?.toLowerCase().contains('testnet') ?? false,
|
isTestnet: info.network?.toLowerCase().contains('testnet') ?? false,
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,9 +6,9 @@ cd "$(dirname "$0")"
|
||||||
|
|
||||||
if [[ ! -d "monero_c" ]];
|
if [[ ! -d "monero_c" ]];
|
||||||
then
|
then
|
||||||
git clone https://github.com/mrcyjanek/monero_c --branch rewrite-wip
|
git clone https://github.com/mrcyjanek/monero_c --branch master
|
||||||
cd monero_c
|
cd monero_c
|
||||||
git checkout e0891d041216099699043da6ac9d08320274b3c6
|
git checkout 292bd2181ab048b2505126e52f32de5f7812e707
|
||||||
git reset --hard
|
git reset --hard
|
||||||
git submodule update --init --force --recursive
|
git submodule update --init --force --recursive
|
||||||
./apply_patches.sh monero
|
./apply_patches.sh monero
|
||||||
|
|
|
@ -275,20 +275,22 @@ import 'package:cw_core/output_info.dart';
|
||||||
import 'package:cake_wallet/view_model/send/output.dart';
|
import 'package:cake_wallet/view_model/send/output.dart';
|
||||||
import 'package:cw_core/wallet_service.dart';
|
import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as ledger;
|
||||||
import 'package:polyseed/polyseed.dart';""";
|
import 'package:polyseed/polyseed.dart';""";
|
||||||
const moneroCWHeaders = """
|
const moneroCWHeaders = """
|
||||||
|
import 'package:cw_core/account.dart' as monero_account;
|
||||||
import 'package:cw_core/get_height_by_date.dart';
|
import 'package:cw_core/get_height_by_date.dart';
|
||||||
import 'package:cw_core/monero_amount_format.dart';
|
import 'package:cw_core/monero_amount_format.dart';
|
||||||
import 'package:cw_core/monero_transaction_priority.dart';
|
import 'package:cw_core/monero_transaction_priority.dart';
|
||||||
|
import 'package:cw_monero/api/wallet_manager.dart';
|
||||||
|
import 'package:cw_monero/api/wallet.dart' as monero_wallet_api;
|
||||||
|
import 'package:cw_monero/ledger.dart';
|
||||||
import 'package:cw_monero/monero_unspent.dart';
|
import 'package:cw_monero/monero_unspent.dart';
|
||||||
import 'package:cw_monero/api/account_list.dart';
|
import 'package:cw_monero/api/account_list.dart';
|
||||||
import 'package:cw_monero/monero_wallet_service.dart';
|
import 'package:cw_monero/monero_wallet_service.dart';
|
||||||
import 'package:cw_monero/api/wallet_manager.dart';
|
|
||||||
import 'package:cw_monero/monero_wallet.dart';
|
import 'package:cw_monero/monero_wallet.dart';
|
||||||
import 'package:cw_monero/monero_transaction_info.dart';
|
import 'package:cw_monero/monero_transaction_info.dart';
|
||||||
import 'package:cw_monero/monero_transaction_creation_credentials.dart';
|
import 'package:cw_monero/monero_transaction_creation_credentials.dart';
|
||||||
import 'package:cw_core/account.dart' as monero_account;
|
|
||||||
import 'package:cw_monero/api/wallet.dart' as monero_wallet_api;
|
|
||||||
import 'package:cw_monero/mnemonics/english.dart';
|
import 'package:cw_monero/mnemonics/english.dart';
|
||||||
import 'package:cw_monero/mnemonics/chinese_simplified.dart';
|
import 'package:cw_monero/mnemonics/chinese_simplified.dart';
|
||||||
import 'package:cw_monero/mnemonics/dutch.dart';
|
import 'package:cw_monero/mnemonics/dutch.dart';
|
||||||
|
@ -400,6 +402,7 @@ abstract class Monero {
|
||||||
required String language,
|
required String language,
|
||||||
required int height});
|
required int height});
|
||||||
WalletCredentials createMoneroRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic});
|
WalletCredentials createMoneroRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic});
|
||||||
|
WalletCredentials createMoneroRestoreWalletFromHardwareCredentials({required String name, required String password, required int height, required ledger.LedgerConnection ledgerConnection});
|
||||||
WalletCredentials createMoneroNewWalletCredentials({required String name, required String language, required bool isPolyseed, String? password});
|
WalletCredentials createMoneroNewWalletCredentials({required String name, required String language, required bool isPolyseed, String? password});
|
||||||
Map<String, String> getKeys(Object wallet);
|
Map<String, String> getKeys(Object wallet);
|
||||||
int? getRestoreHeight(Object wallet);
|
int? getRestoreHeight(Object wallet);
|
||||||
|
@ -416,6 +419,8 @@ abstract class Monero {
|
||||||
int getTransactionInfoAccountId(TransactionInfo tx);
|
int getTransactionInfoAccountId(TransactionInfo tx);
|
||||||
WalletService createMoneroWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
|
WalletService createMoneroWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
|
||||||
Map<String, String> pendingTransactionInfo(Object transaction);
|
Map<String, String> pendingTransactionInfo(Object transaction);
|
||||||
|
void setLedgerConnection(Object wallet, ledger.LedgerConnection connection);
|
||||||
|
void setGlobalLedgerConnection(ledger.LedgerConnection connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class MoneroSubaddressList {
|
abstract class MoneroSubaddressList {
|
||||||
|
|
Loading…
Reference in a new issue