mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-03-22 07:08:49 +00:00
config changes
This commit is contained in:
parent
359c5e8a9a
commit
e3624880c5
35 changed files with 2108 additions and 344 deletions
83
cw_nano/lib/api/account_list.dart
Normal file
83
cw_nano/lib/api/account_list.dart
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
import 'package:cw_nano/api/signatures.dart';
|
||||||
|
import 'package:cw_nano/api/types.dart';
|
||||||
|
import 'package:cw_nano/api/monero_api.dart';
|
||||||
|
import 'package:cw_nano/api/structs/account_row.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:cw_nano/api/wallet.dart';
|
||||||
|
|
||||||
|
final accountSizeNative = moneroApi
|
||||||
|
.lookup<NativeFunction<account_size>>('account_size')
|
||||||
|
.asFunction<SubaddressSize>();
|
||||||
|
|
||||||
|
final accountRefreshNative = moneroApi
|
||||||
|
.lookup<NativeFunction<account_refresh>>('account_refresh')
|
||||||
|
.asFunction<AccountRefresh>();
|
||||||
|
|
||||||
|
final accountGetAllNative = moneroApi
|
||||||
|
.lookup<NativeFunction<account_get_all>>('account_get_all')
|
||||||
|
.asFunction<AccountGetAll>();
|
||||||
|
|
||||||
|
final accountAddNewNative = moneroApi
|
||||||
|
.lookup<NativeFunction<account_add_new>>('account_add_row')
|
||||||
|
.asFunction<AccountAddNew>();
|
||||||
|
|
||||||
|
final accountSetLabelNative = moneroApi
|
||||||
|
.lookup<NativeFunction<account_set_label>>('account_set_label_row')
|
||||||
|
.asFunction<AccountSetLabel>();
|
||||||
|
|
||||||
|
bool isUpdating = false;
|
||||||
|
|
||||||
|
void refreshAccounts() {
|
||||||
|
try {
|
||||||
|
isUpdating = true;
|
||||||
|
accountRefreshNative();
|
||||||
|
isUpdating = false;
|
||||||
|
} catch (e) {
|
||||||
|
isUpdating = false;
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<AccountRow> getAllAccount() {
|
||||||
|
final size = accountSizeNative();
|
||||||
|
final accountAddressesPointer = accountGetAllNative();
|
||||||
|
final accountAddresses = accountAddressesPointer.asTypedList(size);
|
||||||
|
|
||||||
|
return accountAddresses
|
||||||
|
.map((addr) => Pointer<AccountRow>.fromAddress(addr).ref)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addAccountSync({required String label}) {
|
||||||
|
final labelPointer = label.toNativeUtf8();
|
||||||
|
accountAddNewNative(labelPointer);
|
||||||
|
calloc.free(labelPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLabelForAccountSync({required int accountIndex, required String label}) {
|
||||||
|
final labelPointer = label.toNativeUtf8();
|
||||||
|
accountSetLabelNative(accountIndex, labelPointer);
|
||||||
|
calloc.free(labelPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _addAccount(String label) => addAccountSync(label: label);
|
||||||
|
|
||||||
|
void _setLabelForAccount(Map<String, dynamic> args) {
|
||||||
|
final label = args['label'] as String;
|
||||||
|
final accountIndex = args['accountIndex'] as int;
|
||||||
|
|
||||||
|
setLabelForAccountSync(label: label, accountIndex: accountIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> addAccount({required String label}) async {
|
||||||
|
await compute(_addAccount, label);
|
||||||
|
await store();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setLabelForAccount({required int accountIndex, required String label}) async {
|
||||||
|
await compute(
|
||||||
|
_setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
|
||||||
|
await store();
|
||||||
|
}
|
8
cw_nano/lib/api/convert_utf8_to_string.dart
Normal file
8
cw_nano/lib/api/convert_utf8_to_string.dart
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
String convertUTF8ToString({required Pointer<Utf8> pointer}) {
|
||||||
|
final str = pointer.toDartString();
|
||||||
|
calloc.free(pointer);
|
||||||
|
return str;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
class ConnectionToNodeException implements Exception {
|
||||||
|
ConnectionToNodeException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
class CreationTransactionException implements Exception {
|
||||||
|
CreationTransactionException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => message;
|
||||||
|
}
|
5
cw_nano/lib/api/exceptions/setup_wallet_exception.dart
Normal file
5
cw_nano/lib/api/exceptions/setup_wallet_exception.dart
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
class SetupWalletException implements Exception {
|
||||||
|
SetupWalletException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
class WalletCreationException implements Exception {
|
||||||
|
WalletCreationException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => message;
|
||||||
|
}
|
8
cw_nano/lib/api/exceptions/wallet_opening_exception.dart
Normal file
8
cw_nano/lib/api/exceptions/wallet_opening_exception.dart
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
class WalletOpeningException implements Exception {
|
||||||
|
WalletOpeningException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => message;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
class WalletRestoreFromKeysException implements Exception {
|
||||||
|
WalletRestoreFromKeysException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
class WalletRestoreFromSeedException implements Exception {
|
||||||
|
WalletRestoreFromSeedException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
}
|
6
cw_nano/lib/api/monero_api.dart
Normal file
6
cw_nano/lib/api/monero_api.dart
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
final DynamicLibrary moneroApi = Platform.isAndroid
|
||||||
|
? DynamicLibrary.open("libcw_monero.so")
|
||||||
|
: DynamicLibrary.open("cw_monero.framework/cw_monero");
|
6
cw_nano/lib/api/monero_output.dart
Normal file
6
cw_nano/lib/api/monero_output.dart
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
class MoneroOutput {
|
||||||
|
MoneroOutput({required this.address, required this.amount});
|
||||||
|
|
||||||
|
final String address;
|
||||||
|
final String amount;
|
||||||
|
}
|
132
cw_nano/lib/api/signatures.dart
Normal file
132
cw_nano/lib/api/signatures.dart
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
||||||
|
import 'package:cw_monero/api/structs/ut8_box.dart';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
typedef create_wallet = Int8 Function(
|
||||||
|
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Pointer<Utf8>);
|
||||||
|
|
||||||
|
typedef restore_wallet_from_seed = Int8 Function(
|
||||||
|
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
|
||||||
|
|
||||||
|
typedef restore_wallet_from_keys = Int8 Function(Pointer<Utf8>, Pointer<Utf8>,
|
||||||
|
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
|
||||||
|
|
||||||
|
typedef is_wallet_exist = Int8 Function(Pointer<Utf8>);
|
||||||
|
|
||||||
|
typedef load_wallet = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Int8);
|
||||||
|
|
||||||
|
typedef error_string = Pointer<Utf8> Function();
|
||||||
|
|
||||||
|
typedef get_filename = Pointer<Utf8> Function();
|
||||||
|
|
||||||
|
typedef get_seed = Pointer<Utf8> Function();
|
||||||
|
|
||||||
|
typedef get_address = Pointer<Utf8> Function(Int32, Int32);
|
||||||
|
|
||||||
|
typedef get_full_balanace = Int64 Function(Int32);
|
||||||
|
|
||||||
|
typedef get_unlocked_balanace = Int64 Function(Int32);
|
||||||
|
|
||||||
|
typedef get_current_height = Int64 Function();
|
||||||
|
|
||||||
|
typedef get_node_height = Int64 Function();
|
||||||
|
|
||||||
|
typedef is_connected = Int8 Function();
|
||||||
|
|
||||||
|
typedef setup_node = Int8 Function(
|
||||||
|
Pointer<Utf8>, Pointer<Utf8>?, Pointer<Utf8>?, Int8, Int8, Pointer<Utf8>);
|
||||||
|
|
||||||
|
typedef start_refresh = Void Function();
|
||||||
|
|
||||||
|
typedef connect_to_node = Int8 Function();
|
||||||
|
|
||||||
|
typedef set_refresh_from_block_height = Void Function(Int64);
|
||||||
|
|
||||||
|
typedef set_recovering_from_seed = Void Function(Int8);
|
||||||
|
|
||||||
|
typedef store_c = Void Function(Pointer<Utf8>);
|
||||||
|
|
||||||
|
typedef set_password = Int8 Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
|
||||||
|
|
||||||
|
typedef set_listener = Void Function();
|
||||||
|
|
||||||
|
typedef get_syncing_height = Int64 Function();
|
||||||
|
|
||||||
|
typedef is_needed_to_refresh = Int8 Function();
|
||||||
|
|
||||||
|
typedef is_new_transaction_exist = Int8 Function();
|
||||||
|
|
||||||
|
typedef subaddrress_size = Int32 Function();
|
||||||
|
|
||||||
|
typedef subaddrress_refresh = Void Function(Int32);
|
||||||
|
|
||||||
|
typedef subaddress_get_all = Pointer<Int64> Function();
|
||||||
|
|
||||||
|
typedef subaddress_add_new = Void Function(
|
||||||
|
Int32 accountIndex, Pointer<Utf8> label);
|
||||||
|
|
||||||
|
typedef subaddress_set_label = Void Function(
|
||||||
|
Int32 accountIndex, Int32 addressIndex, Pointer<Utf8> label);
|
||||||
|
|
||||||
|
typedef account_size = Int32 Function();
|
||||||
|
|
||||||
|
typedef account_refresh = Void Function();
|
||||||
|
|
||||||
|
typedef account_get_all = Pointer<Int64> Function();
|
||||||
|
|
||||||
|
typedef account_add_new = Void Function(Pointer<Utf8> label);
|
||||||
|
|
||||||
|
typedef account_set_label = Void Function(
|
||||||
|
Int32 accountIndex, Pointer<Utf8> label);
|
||||||
|
|
||||||
|
typedef transactions_refresh = Void Function();
|
||||||
|
|
||||||
|
typedef get_tx_key = Pointer<Utf8>? Function(Pointer<Utf8> txId);
|
||||||
|
|
||||||
|
typedef transactions_count = Int64 Function();
|
||||||
|
|
||||||
|
typedef transactions_get_all = Pointer<Int64> Function();
|
||||||
|
|
||||||
|
typedef transaction_create = Int8 Function(
|
||||||
|
Pointer<Utf8> address,
|
||||||
|
Pointer<Utf8> paymentId,
|
||||||
|
Pointer<Utf8> amount,
|
||||||
|
Int8 priorityRaw,
|
||||||
|
Int32 subaddrAccount,
|
||||||
|
Pointer<Utf8Box> error,
|
||||||
|
Pointer<PendingTransactionRaw> pendingTransaction);
|
||||||
|
|
||||||
|
typedef transaction_create_mult_dest = Int8 Function(
|
||||||
|
Pointer<Pointer<Utf8>> addresses,
|
||||||
|
Pointer<Utf8> paymentId,
|
||||||
|
Pointer<Pointer<Utf8>> amounts,
|
||||||
|
Int32 size,
|
||||||
|
Int8 priorityRaw,
|
||||||
|
Int32 subaddrAccount,
|
||||||
|
Pointer<Utf8Box> error,
|
||||||
|
Pointer<PendingTransactionRaw> pendingTransaction);
|
||||||
|
|
||||||
|
typedef transaction_commit = Int8 Function(Pointer<PendingTransactionRaw>, Pointer<Utf8Box>);
|
||||||
|
|
||||||
|
typedef secret_view_key = Pointer<Utf8> Function();
|
||||||
|
|
||||||
|
typedef public_view_key = Pointer<Utf8> Function();
|
||||||
|
|
||||||
|
typedef secret_spend_key = Pointer<Utf8> Function();
|
||||||
|
|
||||||
|
typedef public_spend_key = Pointer<Utf8> Function();
|
||||||
|
|
||||||
|
typedef close_current_wallet = Void Function();
|
||||||
|
|
||||||
|
typedef on_startup = Void Function();
|
||||||
|
|
||||||
|
typedef rescan_blockchain = Void Function();
|
||||||
|
|
||||||
|
typedef get_subaddress_label = Pointer<Utf8> Function(
|
||||||
|
Int32 accountIndex,
|
||||||
|
Int32 addressIndex);
|
||||||
|
|
||||||
|
typedef set_trusted_daemon = Void Function(Int8 trusted);
|
||||||
|
|
||||||
|
typedef trusted_daemon = Int8 Function();
|
12
cw_nano/lib/api/structs/account_row.dart
Normal file
12
cw_nano/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;
|
||||||
|
}
|
39
cw_nano/lib/api/structs/pending_transaction.dart
Normal file
39
cw_nano/lib/api/structs/pending_transaction.dart
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
class PendingTransactionRaw extends Struct {
|
||||||
|
@Int64()
|
||||||
|
external int amount;
|
||||||
|
|
||||||
|
@Int64()
|
||||||
|
external int fee;
|
||||||
|
|
||||||
|
external Pointer<Utf8> hash;
|
||||||
|
|
||||||
|
external Pointer<Utf8> hex;
|
||||||
|
|
||||||
|
external Pointer<Utf8> txKey;
|
||||||
|
|
||||||
|
String getHash() => hash.toDartString();
|
||||||
|
|
||||||
|
String getHex() => hex.toDartString();
|
||||||
|
|
||||||
|
String getKey() => txKey.toDartString();
|
||||||
|
}
|
||||||
|
|
||||||
|
class PendingTransactionDescription {
|
||||||
|
PendingTransactionDescription({
|
||||||
|
required this.amount,
|
||||||
|
required this.fee,
|
||||||
|
required this.hash,
|
||||||
|
required this.hex,
|
||||||
|
required this.txKey,
|
||||||
|
required this.pointerAddress});
|
||||||
|
|
||||||
|
final int amount;
|
||||||
|
final int fee;
|
||||||
|
final String hash;
|
||||||
|
final String hex;
|
||||||
|
final String txKey;
|
||||||
|
final int pointerAddress;
|
||||||
|
}
|
15
cw_nano/lib/api/structs/subaddress_row.dart
Normal file
15
cw_nano/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_nano/lib/api/structs/transaction_info_row.dart
Normal file
41
cw_nano/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_nano/lib/api/structs/ut8_box.dart
Normal file
8
cw_nano/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();
|
||||||
|
}
|
97
cw_nano/lib/api/subaddress_list.dart
Normal file
97
cw_nano/lib/api/subaddress_list.dart
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:cw_monero/api/signatures.dart';
|
||||||
|
import 'package:cw_monero/api/types.dart';
|
||||||
|
import 'package:cw_monero/api/monero_api.dart';
|
||||||
|
import 'package:cw_monero/api/structs/subaddress_row.dart';
|
||||||
|
import 'package:cw_monero/api/wallet.dart';
|
||||||
|
|
||||||
|
final subaddressSizeNative = moneroApi
|
||||||
|
.lookup<NativeFunction<subaddrress_size>>('subaddrress_size')
|
||||||
|
.asFunction<SubaddressSize>();
|
||||||
|
|
||||||
|
final subaddressRefreshNative = moneroApi
|
||||||
|
.lookup<NativeFunction<subaddrress_refresh>>('subaddress_refresh')
|
||||||
|
.asFunction<SubaddressRefresh>();
|
||||||
|
|
||||||
|
final subaddrressGetAllNative = moneroApi
|
||||||
|
.lookup<NativeFunction<subaddress_get_all>>('subaddrress_get_all')
|
||||||
|
.asFunction<SubaddressGetAll>();
|
||||||
|
|
||||||
|
final subaddrressAddNewNative = moneroApi
|
||||||
|
.lookup<NativeFunction<subaddress_add_new>>('subaddress_add_row')
|
||||||
|
.asFunction<SubaddressAddNew>();
|
||||||
|
|
||||||
|
final subaddrressSetLabelNative = moneroApi
|
||||||
|
.lookup<NativeFunction<subaddress_set_label>>('subaddress_set_label')
|
||||||
|
.asFunction<SubaddressSetLabel>();
|
||||||
|
|
||||||
|
bool isUpdating = false;
|
||||||
|
|
||||||
|
void refreshSubaddresses({required int accountIndex}) {
|
||||||
|
try {
|
||||||
|
isUpdating = true;
|
||||||
|
subaddressRefreshNative(accountIndex);
|
||||||
|
isUpdating = false;
|
||||||
|
} catch (e) {
|
||||||
|
isUpdating = false;
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SubaddressRow> getAllSubaddresses() {
|
||||||
|
final size = subaddressSizeNative();
|
||||||
|
final subaddressAddressesPointer = subaddrressGetAllNative();
|
||||||
|
final subaddressAddresses = subaddressAddressesPointer.asTypedList(size);
|
||||||
|
|
||||||
|
return subaddressAddresses
|
||||||
|
.map((addr) => Pointer<SubaddressRow>.fromAddress(addr).ref)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addSubaddressSync({required int accountIndex, required String label}) {
|
||||||
|
final labelPointer = label.toNativeUtf8();
|
||||||
|
subaddrressAddNewNative(accountIndex, labelPointer);
|
||||||
|
calloc.free(labelPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLabelForSubaddressSync(
|
||||||
|
{required int accountIndex, required int addressIndex, required String label}) {
|
||||||
|
final labelPointer = label.toNativeUtf8();
|
||||||
|
|
||||||
|
subaddrressSetLabelNative(accountIndex, addressIndex, labelPointer);
|
||||||
|
calloc.free(labelPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _addSubaddress(Map<String, dynamic> args) {
|
||||||
|
final label = args['label'] as String;
|
||||||
|
final accountIndex = args['accountIndex'] as int;
|
||||||
|
|
||||||
|
addSubaddressSync(accountIndex: accountIndex, label: label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setLabelForSubaddress(Map<String, dynamic> args) {
|
||||||
|
final label = args['label'] as String;
|
||||||
|
final accountIndex = args['accountIndex'] as int;
|
||||||
|
final addressIndex = args['addressIndex'] as int;
|
||||||
|
|
||||||
|
setLabelForSubaddressSync(
|
||||||
|
accountIndex: accountIndex, addressIndex: addressIndex, label: label);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> addSubaddress({required int accountIndex, required String label}) async {
|
||||||
|
await compute<Map<String, Object>, void>(
|
||||||
|
_addSubaddress, {'accountIndex': accountIndex, 'label': label});
|
||||||
|
await store();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setLabelForSubaddress(
|
||||||
|
{required int accountIndex, required int addressIndex, required String label}) async {
|
||||||
|
await compute<Map<String, Object>, void>(_setLabelForSubaddress, {
|
||||||
|
'accountIndex': accountIndex,
|
||||||
|
'addressIndex': addressIndex,
|
||||||
|
'label': label
|
||||||
|
});
|
||||||
|
await store();
|
||||||
|
}
|
234
cw_nano/lib/api/transaction_history.dart
Normal file
234
cw_nano/lib/api/transaction_history.dart
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:cw_monero/api/convert_utf8_to_string.dart';
|
||||||
|
import 'package:cw_monero/api/monero_output.dart';
|
||||||
|
import 'package:cw_monero/api/structs/ut8_box.dart';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:cw_monero/api/signatures.dart';
|
||||||
|
import 'package:cw_monero/api/types.dart';
|
||||||
|
import 'package:cw_monero/api/monero_api.dart';
|
||||||
|
import 'package:cw_monero/api/structs/transaction_info_row.dart';
|
||||||
|
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
||||||
|
import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart';
|
||||||
|
|
||||||
|
final transactionsRefreshNative = moneroApi
|
||||||
|
.lookup<NativeFunction<transactions_refresh>>('transactions_refresh')
|
||||||
|
.asFunction<TransactionsRefresh>();
|
||||||
|
|
||||||
|
final transactionsCountNative = moneroApi
|
||||||
|
.lookup<NativeFunction<transactions_count>>('transactions_count')
|
||||||
|
.asFunction<TransactionsCount>();
|
||||||
|
|
||||||
|
final transactionsGetAllNative = moneroApi
|
||||||
|
.lookup<NativeFunction<transactions_get_all>>('transactions_get_all')
|
||||||
|
.asFunction<TransactionsGetAll>();
|
||||||
|
|
||||||
|
final transactionCreateNative = moneroApi
|
||||||
|
.lookup<NativeFunction<transaction_create>>('transaction_create')
|
||||||
|
.asFunction<TransactionCreate>();
|
||||||
|
|
||||||
|
final transactionCreateMultDestNative = moneroApi
|
||||||
|
.lookup<NativeFunction<transaction_create_mult_dest>>('transaction_create_mult_dest')
|
||||||
|
.asFunction<TransactionCreateMultDest>();
|
||||||
|
|
||||||
|
final transactionCommitNative = moneroApi
|
||||||
|
.lookup<NativeFunction<transaction_commit>>('transaction_commit')
|
||||||
|
.asFunction<TransactionCommit>();
|
||||||
|
|
||||||
|
final getTxKeyNative = moneroApi
|
||||||
|
.lookup<NativeFunction<get_tx_key>>('get_tx_key')
|
||||||
|
.asFunction<GetTxKey>();
|
||||||
|
|
||||||
|
String getTxKey(String txId) {
|
||||||
|
final txIdPointer = txId.toNativeUtf8();
|
||||||
|
final keyPointer = getTxKeyNative(txIdPointer);
|
||||||
|
|
||||||
|
calloc.free(txIdPointer);
|
||||||
|
|
||||||
|
if (keyPointer != null) {
|
||||||
|
return convertUTF8ToString(pointer: keyPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
void refreshTransactions() => transactionsRefreshNative();
|
||||||
|
|
||||||
|
int countOfTransactions() => transactionsCountNative();
|
||||||
|
|
||||||
|
List<TransactionInfoRow> getAllTransations() {
|
||||||
|
final size = transactionsCountNative();
|
||||||
|
final transactionsPointer = transactionsGetAllNative();
|
||||||
|
final transactionsAddresses = transactionsPointer.asTypedList(size);
|
||||||
|
|
||||||
|
return transactionsAddresses
|
||||||
|
.map((addr) => Pointer<TransactionInfoRow>.fromAddress(addr).ref)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
PendingTransactionDescription createTransactionSync(
|
||||||
|
{required String address,
|
||||||
|
required String paymentId,
|
||||||
|
required int priorityRaw,
|
||||||
|
String? amount,
|
||||||
|
int accountIndex = 0}) {
|
||||||
|
final addressPointer = address.toNativeUtf8();
|
||||||
|
final paymentIdPointer = paymentId.toNativeUtf8();
|
||||||
|
final amountPointer = amount != null ? amount.toNativeUtf8() : nullptr;
|
||||||
|
final errorMessagePointer = calloc<Utf8Box>();
|
||||||
|
final pendingTransactionRawPointer = calloc<PendingTransactionRaw>();
|
||||||
|
final created = transactionCreateNative(
|
||||||
|
addressPointer,
|
||||||
|
paymentIdPointer,
|
||||||
|
amountPointer,
|
||||||
|
priorityRaw,
|
||||||
|
accountIndex,
|
||||||
|
errorMessagePointer,
|
||||||
|
pendingTransactionRawPointer) !=
|
||||||
|
0;
|
||||||
|
|
||||||
|
calloc.free(addressPointer);
|
||||||
|
calloc.free(paymentIdPointer);
|
||||||
|
|
||||||
|
if (amountPointer != nullptr) {
|
||||||
|
calloc.free(amountPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!created) {
|
||||||
|
final message = errorMessagePointer.ref.getValue();
|
||||||
|
calloc.free(errorMessagePointer);
|
||||||
|
throw CreationTransactionException(message: message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PendingTransactionDescription(
|
||||||
|
amount: pendingTransactionRawPointer.ref.amount,
|
||||||
|
fee: pendingTransactionRawPointer.ref.fee,
|
||||||
|
hash: pendingTransactionRawPointer.ref.getHash(),
|
||||||
|
hex: pendingTransactionRawPointer.ref.getHex(),
|
||||||
|
txKey: pendingTransactionRawPointer.ref.getKey(),
|
||||||
|
pointerAddress: pendingTransactionRawPointer.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
PendingTransactionDescription createTransactionMultDestSync(
|
||||||
|
{required List<MoneroOutput> outputs,
|
||||||
|
required String paymentId,
|
||||||
|
required int priorityRaw,
|
||||||
|
int accountIndex = 0}) {
|
||||||
|
final int size = outputs.length;
|
||||||
|
final List<Pointer<Utf8>> addressesPointers = outputs.map((output) =>
|
||||||
|
output.address.toNativeUtf8()).toList();
|
||||||
|
final Pointer<Pointer<Utf8>> addressesPointerPointer = calloc(size);
|
||||||
|
final List<Pointer<Utf8>> amountsPointers = outputs.map((output) =>
|
||||||
|
output.amount.toNativeUtf8()).toList();
|
||||||
|
final Pointer<Pointer<Utf8>> amountsPointerPointer = calloc(size);
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
addressesPointerPointer[i] = addressesPointers[i];
|
||||||
|
amountsPointerPointer[i] = amountsPointers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
final paymentIdPointer = paymentId.toNativeUtf8();
|
||||||
|
final errorMessagePointer = calloc<Utf8Box>();
|
||||||
|
final pendingTransactionRawPointer = calloc<PendingTransactionRaw>();
|
||||||
|
final created = transactionCreateMultDestNative(
|
||||||
|
addressesPointerPointer,
|
||||||
|
paymentIdPointer,
|
||||||
|
amountsPointerPointer,
|
||||||
|
size,
|
||||||
|
priorityRaw,
|
||||||
|
accountIndex,
|
||||||
|
errorMessagePointer,
|
||||||
|
pendingTransactionRawPointer) !=
|
||||||
|
0;
|
||||||
|
|
||||||
|
calloc.free(addressesPointerPointer);
|
||||||
|
calloc.free(amountsPointerPointer);
|
||||||
|
|
||||||
|
addressesPointers.forEach((element) => calloc.free(element));
|
||||||
|
amountsPointers.forEach((element) => calloc.free(element));
|
||||||
|
|
||||||
|
calloc.free(paymentIdPointer);
|
||||||
|
|
||||||
|
if (!created) {
|
||||||
|
final message = errorMessagePointer.ref.getValue();
|
||||||
|
calloc.free(errorMessagePointer);
|
||||||
|
throw CreationTransactionException(message: message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PendingTransactionDescription(
|
||||||
|
amount: pendingTransactionRawPointer.ref.amount,
|
||||||
|
fee: pendingTransactionRawPointer.ref.fee,
|
||||||
|
hash: pendingTransactionRawPointer.ref.getHash(),
|
||||||
|
hex: pendingTransactionRawPointer.ref.getHex(),
|
||||||
|
txKey: pendingTransactionRawPointer.ref.getKey(),
|
||||||
|
pointerAddress: pendingTransactionRawPointer.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void commitTransactionFromPointerAddress({required int address}) => commitTransaction(
|
||||||
|
transactionPointer: Pointer<PendingTransactionRaw>.fromAddress(address));
|
||||||
|
|
||||||
|
void commitTransaction({required Pointer<PendingTransactionRaw> transactionPointer}) {
|
||||||
|
final errorMessagePointer = calloc<Utf8Box>();
|
||||||
|
final isCommited =
|
||||||
|
transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
|
||||||
|
|
||||||
|
if (!isCommited) {
|
||||||
|
final message = errorMessagePointer.ref.getValue();
|
||||||
|
calloc.free(errorMessagePointer);
|
||||||
|
throw CreationTransactionException(message: message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PendingTransactionDescription _createTransactionSync(Map args) {
|
||||||
|
final address = args['address'] as String;
|
||||||
|
final paymentId = args['paymentId'] as String;
|
||||||
|
final amount = args['amount'] as String?;
|
||||||
|
final priorityRaw = args['priorityRaw'] as int;
|
||||||
|
final accountIndex = args['accountIndex'] as int;
|
||||||
|
|
||||||
|
return createTransactionSync(
|
||||||
|
address: address,
|
||||||
|
paymentId: paymentId,
|
||||||
|
amount: amount,
|
||||||
|
priorityRaw: priorityRaw,
|
||||||
|
accountIndex: accountIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
PendingTransactionDescription _createTransactionMultDestSync(Map args) {
|
||||||
|
final outputs = args['outputs'] as List<MoneroOutput>;
|
||||||
|
final paymentId = args['paymentId'] as String;
|
||||||
|
final priorityRaw = args['priorityRaw'] as int;
|
||||||
|
final accountIndex = args['accountIndex'] as int;
|
||||||
|
|
||||||
|
return createTransactionMultDestSync(
|
||||||
|
outputs: outputs,
|
||||||
|
paymentId: paymentId,
|
||||||
|
priorityRaw: priorityRaw,
|
||||||
|
accountIndex: accountIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<PendingTransactionDescription> createTransaction(
|
||||||
|
{required String address,
|
||||||
|
required int priorityRaw,
|
||||||
|
String? amount,
|
||||||
|
String paymentId = '',
|
||||||
|
int accountIndex = 0}) =>
|
||||||
|
compute(_createTransactionSync, {
|
||||||
|
'address': address,
|
||||||
|
'paymentId': paymentId,
|
||||||
|
'amount': amount,
|
||||||
|
'priorityRaw': priorityRaw,
|
||||||
|
'accountIndex': accountIndex
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<PendingTransactionDescription> createTransactionMultDest(
|
||||||
|
{required List<MoneroOutput> outputs,
|
||||||
|
required int priorityRaw,
|
||||||
|
String paymentId = '',
|
||||||
|
int accountIndex = 0}) =>
|
||||||
|
compute(_createTransactionMultDestSync, {
|
||||||
|
'outputs': outputs,
|
||||||
|
'paymentId': paymentId,
|
||||||
|
'priorityRaw': priorityRaw,
|
||||||
|
'accountIndex': accountIndex
|
||||||
|
});
|
130
cw_nano/lib/api/types.dart
Normal file
130
cw_nano/lib/api/types.dart
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
||||||
|
import 'package:cw_monero/api/structs/ut8_box.dart';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
typedef CreateWallet = int Function(
|
||||||
|
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, Pointer<Utf8>);
|
||||||
|
|
||||||
|
typedef RestoreWalletFromSeed = int Function(
|
||||||
|
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
|
||||||
|
|
||||||
|
typedef RestoreWalletFromKeys = int Function(Pointer<Utf8>, Pointer<Utf8>,
|
||||||
|
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
|
||||||
|
|
||||||
|
typedef IsWalletExist = int Function(Pointer<Utf8>);
|
||||||
|
|
||||||
|
typedef LoadWallet = int Function(Pointer<Utf8>, Pointer<Utf8>, int);
|
||||||
|
|
||||||
|
typedef ErrorString = Pointer<Utf8> Function();
|
||||||
|
|
||||||
|
typedef GetFilename = Pointer<Utf8> Function();
|
||||||
|
|
||||||
|
typedef GetSeed = Pointer<Utf8> Function();
|
||||||
|
|
||||||
|
typedef GetAddress = Pointer<Utf8> Function(int, int);
|
||||||
|
|
||||||
|
typedef GetFullBalance = int Function(int);
|
||||||
|
|
||||||
|
typedef GetUnlockedBalance = int Function(int);
|
||||||
|
|
||||||
|
typedef GetCurrentHeight = int Function();
|
||||||
|
|
||||||
|
typedef GetNodeHeight = int Function();
|
||||||
|
|
||||||
|
typedef IsConnected = int Function();
|
||||||
|
|
||||||
|
typedef SetupNode = int Function(
|
||||||
|
Pointer<Utf8>, Pointer<Utf8>?, Pointer<Utf8>?, int, int, Pointer<Utf8>);
|
||||||
|
|
||||||
|
typedef StartRefresh = void Function();
|
||||||
|
|
||||||
|
typedef ConnectToNode = int Function();
|
||||||
|
|
||||||
|
typedef SetRefreshFromBlockHeight = void Function(int);
|
||||||
|
|
||||||
|
typedef SetRecoveringFromSeed = void Function(int);
|
||||||
|
|
||||||
|
typedef Store = void Function(Pointer<Utf8>);
|
||||||
|
|
||||||
|
typedef SetPassword = int Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
|
||||||
|
|
||||||
|
typedef SetListener = void Function();
|
||||||
|
|
||||||
|
typedef GetSyncingHeight = int Function();
|
||||||
|
|
||||||
|
typedef IsNeededToRefresh = int Function();
|
||||||
|
|
||||||
|
typedef IsNewTransactionExist = int Function();
|
||||||
|
|
||||||
|
typedef SubaddressSize = int Function();
|
||||||
|
|
||||||
|
typedef SubaddressRefresh = void Function(int);
|
||||||
|
|
||||||
|
typedef SubaddressGetAll = Pointer<Int64> Function();
|
||||||
|
|
||||||
|
typedef SubaddressAddNew = void Function(int accountIndex, Pointer<Utf8> label);
|
||||||
|
|
||||||
|
typedef SubaddressSetLabel = void Function(
|
||||||
|
int accountIndex, int addressIndex, Pointer<Utf8> label);
|
||||||
|
|
||||||
|
typedef AccountSize = int Function();
|
||||||
|
|
||||||
|
typedef AccountRefresh = void Function();
|
||||||
|
|
||||||
|
typedef AccountGetAll = Pointer<Int64> Function();
|
||||||
|
|
||||||
|
typedef AccountAddNew = void Function(Pointer<Utf8> label);
|
||||||
|
|
||||||
|
typedef AccountSetLabel = void Function(int accountIndex, Pointer<Utf8> label);
|
||||||
|
|
||||||
|
typedef TransactionsRefresh = void Function();
|
||||||
|
|
||||||
|
typedef GetTxKey = Pointer<Utf8>? Function(Pointer<Utf8> txId);
|
||||||
|
|
||||||
|
typedef TransactionsCount = int Function();
|
||||||
|
|
||||||
|
typedef TransactionsGetAll = Pointer<Int64> Function();
|
||||||
|
|
||||||
|
typedef TransactionCreate = int Function(
|
||||||
|
Pointer<Utf8> address,
|
||||||
|
Pointer<Utf8> paymentId,
|
||||||
|
Pointer<Utf8> amount,
|
||||||
|
int priorityRaw,
|
||||||
|
int subaddrAccount,
|
||||||
|
Pointer<Utf8Box> error,
|
||||||
|
Pointer<PendingTransactionRaw> pendingTransaction);
|
||||||
|
|
||||||
|
typedef TransactionCreateMultDest = int Function(
|
||||||
|
Pointer<Pointer<Utf8>> addresses,
|
||||||
|
Pointer<Utf8> paymentId,
|
||||||
|
Pointer<Pointer<Utf8>> amounts,
|
||||||
|
int size,
|
||||||
|
int priorityRaw,
|
||||||
|
int subaddrAccount,
|
||||||
|
Pointer<Utf8Box> error,
|
||||||
|
Pointer<PendingTransactionRaw> pendingTransaction);
|
||||||
|
|
||||||
|
typedef TransactionCommit = int Function(Pointer<PendingTransactionRaw>, Pointer<Utf8Box>);
|
||||||
|
|
||||||
|
typedef SecretViewKey = Pointer<Utf8> Function();
|
||||||
|
|
||||||
|
typedef PublicViewKey = Pointer<Utf8> Function();
|
||||||
|
|
||||||
|
typedef SecretSpendKey = Pointer<Utf8> Function();
|
||||||
|
|
||||||
|
typedef PublicSpendKey = Pointer<Utf8> Function();
|
||||||
|
|
||||||
|
typedef CloseCurrentWallet = void Function();
|
||||||
|
|
||||||
|
typedef OnStartup = void Function();
|
||||||
|
|
||||||
|
typedef RescanBlockchainAsync = void Function();
|
||||||
|
|
||||||
|
typedef GetSubaddressLabel = Pointer<Utf8> Function(
|
||||||
|
int accountIndex,
|
||||||
|
int addressIndex);
|
||||||
|
|
||||||
|
typedef SetTrustedDaemon = void Function(int);
|
||||||
|
|
||||||
|
typedef TrustedDaemon = int Function();
|
374
cw_nano/lib/api/wallet.dart
Normal file
374
cw_nano/lib/api/wallet.dart
Normal file
|
@ -0,0 +1,374 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
import 'package:cw_monero/api/structs/ut8_box.dart';
|
||||||
|
import 'package:cw_monero/api/convert_utf8_to_string.dart';
|
||||||
|
import 'package:cw_monero/api/signatures.dart';
|
||||||
|
import 'package:cw_monero/api/types.dart';
|
||||||
|
import 'package:cw_monero/api/monero_api.dart';
|
||||||
|
import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
int _boolToInt(bool value) => value ? 1 : 0;
|
||||||
|
|
||||||
|
final getFileNameNative = moneroApi
|
||||||
|
.lookup<NativeFunction<get_filename>>('get_filename')
|
||||||
|
.asFunction<GetFilename>();
|
||||||
|
|
||||||
|
final getSeedNative =
|
||||||
|
moneroApi.lookup<NativeFunction<get_seed>>('seed').asFunction<GetSeed>();
|
||||||
|
|
||||||
|
final getAddressNative = moneroApi
|
||||||
|
.lookup<NativeFunction<get_address>>('get_address')
|
||||||
|
.asFunction<GetAddress>();
|
||||||
|
|
||||||
|
final getFullBalanceNative = moneroApi
|
||||||
|
.lookup<NativeFunction<get_full_balanace>>('get_full_balance')
|
||||||
|
.asFunction<GetFullBalance>();
|
||||||
|
|
||||||
|
final getUnlockedBalanceNative = moneroApi
|
||||||
|
.lookup<NativeFunction<get_unlocked_balanace>>('get_unlocked_balance')
|
||||||
|
.asFunction<GetUnlockedBalance>();
|
||||||
|
|
||||||
|
final getCurrentHeightNative = moneroApi
|
||||||
|
.lookup<NativeFunction<get_current_height>>('get_current_height')
|
||||||
|
.asFunction<GetCurrentHeight>();
|
||||||
|
|
||||||
|
final getNodeHeightNative = moneroApi
|
||||||
|
.lookup<NativeFunction<get_node_height>>('get_node_height')
|
||||||
|
.asFunction<GetNodeHeight>();
|
||||||
|
|
||||||
|
final isConnectedNative = moneroApi
|
||||||
|
.lookup<NativeFunction<is_connected>>('is_connected')
|
||||||
|
.asFunction<IsConnected>();
|
||||||
|
|
||||||
|
final setupNodeNative = moneroApi
|
||||||
|
.lookup<NativeFunction<setup_node>>('setup_node')
|
||||||
|
.asFunction<SetupNode>();
|
||||||
|
|
||||||
|
final startRefreshNative = moneroApi
|
||||||
|
.lookup<NativeFunction<start_refresh>>('start_refresh')
|
||||||
|
.asFunction<StartRefresh>();
|
||||||
|
|
||||||
|
final connecToNodeNative = moneroApi
|
||||||
|
.lookup<NativeFunction<connect_to_node>>('connect_to_node')
|
||||||
|
.asFunction<ConnectToNode>();
|
||||||
|
|
||||||
|
final setRefreshFromBlockHeightNative = moneroApi
|
||||||
|
.lookup<NativeFunction<set_refresh_from_block_height>>(
|
||||||
|
'set_refresh_from_block_height')
|
||||||
|
.asFunction<SetRefreshFromBlockHeight>();
|
||||||
|
|
||||||
|
final setRecoveringFromSeedNative = moneroApi
|
||||||
|
.lookup<NativeFunction<set_recovering_from_seed>>(
|
||||||
|
'set_recovering_from_seed')
|
||||||
|
.asFunction<SetRecoveringFromSeed>();
|
||||||
|
|
||||||
|
final storeNative =
|
||||||
|
moneroApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
|
||||||
|
|
||||||
|
final setPasswordNative =
|
||||||
|
moneroApi.lookup<NativeFunction<set_password>>('set_password').asFunction<SetPassword>();
|
||||||
|
|
||||||
|
final setListenerNative = moneroApi
|
||||||
|
.lookup<NativeFunction<set_listener>>('set_listener')
|
||||||
|
.asFunction<SetListener>();
|
||||||
|
|
||||||
|
final getSyncingHeightNative = moneroApi
|
||||||
|
.lookup<NativeFunction<get_syncing_height>>('get_syncing_height')
|
||||||
|
.asFunction<GetSyncingHeight>();
|
||||||
|
|
||||||
|
final isNeededToRefreshNative = moneroApi
|
||||||
|
.lookup<NativeFunction<is_needed_to_refresh>>('is_needed_to_refresh')
|
||||||
|
.asFunction<IsNeededToRefresh>();
|
||||||
|
|
||||||
|
final isNewTransactionExistNative = moneroApi
|
||||||
|
.lookup<NativeFunction<is_new_transaction_exist>>(
|
||||||
|
'is_new_transaction_exist')
|
||||||
|
.asFunction<IsNewTransactionExist>();
|
||||||
|
|
||||||
|
final getSecretViewKeyNative = moneroApi
|
||||||
|
.lookup<NativeFunction<secret_view_key>>('secret_view_key')
|
||||||
|
.asFunction<SecretViewKey>();
|
||||||
|
|
||||||
|
final getPublicViewKeyNative = moneroApi
|
||||||
|
.lookup<NativeFunction<public_view_key>>('public_view_key')
|
||||||
|
.asFunction<PublicViewKey>();
|
||||||
|
|
||||||
|
final getSecretSpendKeyNative = moneroApi
|
||||||
|
.lookup<NativeFunction<secret_spend_key>>('secret_spend_key')
|
||||||
|
.asFunction<SecretSpendKey>();
|
||||||
|
|
||||||
|
final getPublicSpendKeyNative = moneroApi
|
||||||
|
.lookup<NativeFunction<secret_view_key>>('public_spend_key')
|
||||||
|
.asFunction<PublicSpendKey>();
|
||||||
|
|
||||||
|
final closeCurrentWalletNative = moneroApi
|
||||||
|
.lookup<NativeFunction<close_current_wallet>>('close_current_wallet')
|
||||||
|
.asFunction<CloseCurrentWallet>();
|
||||||
|
|
||||||
|
final onStartupNative = moneroApi
|
||||||
|
.lookup<NativeFunction<on_startup>>('on_startup')
|
||||||
|
.asFunction<OnStartup>();
|
||||||
|
|
||||||
|
final rescanBlockchainAsyncNative = moneroApi
|
||||||
|
.lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain')
|
||||||
|
.asFunction<RescanBlockchainAsync>();
|
||||||
|
|
||||||
|
final getSubaddressLabelNative = moneroApi
|
||||||
|
.lookup<NativeFunction<get_subaddress_label>>('get_subaddress_label')
|
||||||
|
.asFunction<GetSubaddressLabel>();
|
||||||
|
|
||||||
|
final setTrustedDaemonNative = moneroApi
|
||||||
|
.lookup<NativeFunction<set_trusted_daemon>>('set_trusted_daemon')
|
||||||
|
.asFunction<SetTrustedDaemon>();
|
||||||
|
|
||||||
|
final trustedDaemonNative = moneroApi
|
||||||
|
.lookup<NativeFunction<trusted_daemon>>('trusted_daemon')
|
||||||
|
.asFunction<TrustedDaemon>();
|
||||||
|
|
||||||
|
int getSyncingHeight() => getSyncingHeightNative();
|
||||||
|
|
||||||
|
bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
|
||||||
|
|
||||||
|
bool isNewTransactionExist() => isNewTransactionExistNative() != 0;
|
||||||
|
|
||||||
|
String getFilename() => convertUTF8ToString(pointer: getFileNameNative());
|
||||||
|
|
||||||
|
String getSeed() => convertUTF8ToString(pointer: getSeedNative());
|
||||||
|
|
||||||
|
String getAddress({int accountIndex = 0, int addressIndex = 0}) =>
|
||||||
|
convertUTF8ToString(pointer: getAddressNative(accountIndex, addressIndex));
|
||||||
|
|
||||||
|
int getFullBalance({int accountIndex = 0}) =>
|
||||||
|
getFullBalanceNative(accountIndex);
|
||||||
|
|
||||||
|
int getUnlockedBalance({int accountIndex = 0}) =>
|
||||||
|
getUnlockedBalanceNative(accountIndex);
|
||||||
|
|
||||||
|
int getCurrentHeight() => getCurrentHeightNative();
|
||||||
|
|
||||||
|
int getNodeHeightSync() => getNodeHeightNative();
|
||||||
|
|
||||||
|
bool isConnectedSync() => isConnectedNative() != 0;
|
||||||
|
|
||||||
|
bool setupNodeSync(
|
||||||
|
{required String address,
|
||||||
|
String? login,
|
||||||
|
String? password,
|
||||||
|
bool useSSL = false,
|
||||||
|
bool isLightWallet = false}) {
|
||||||
|
final addressPointer = address.toNativeUtf8();
|
||||||
|
Pointer<Utf8>? loginPointer;
|
||||||
|
Pointer<Utf8>? passwordPointer;
|
||||||
|
|
||||||
|
if (login != null) {
|
||||||
|
loginPointer = login.toNativeUtf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password != null) {
|
||||||
|
passwordPointer = password.toNativeUtf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
final errorMessagePointer = ''.toNativeUtf8();
|
||||||
|
final isSetupNode = setupNodeNative(
|
||||||
|
addressPointer,
|
||||||
|
loginPointer,
|
||||||
|
passwordPointer,
|
||||||
|
_boolToInt(useSSL),
|
||||||
|
_boolToInt(isLightWallet),
|
||||||
|
errorMessagePointer) !=
|
||||||
|
0;
|
||||||
|
|
||||||
|
calloc.free(addressPointer);
|
||||||
|
|
||||||
|
if (loginPointer != null) {
|
||||||
|
calloc.free(loginPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (passwordPointer != null) {
|
||||||
|
calloc.free(passwordPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSetupNode) {
|
||||||
|
throw SetupWalletException(
|
||||||
|
message: convertUTF8ToString(pointer: errorMessagePointer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return isSetupNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void startRefreshSync() => startRefreshNative();
|
||||||
|
|
||||||
|
Future<bool> connectToNode() async => connecToNodeNative() != 0;
|
||||||
|
|
||||||
|
void setRefreshFromBlockHeight({required int height}) =>
|
||||||
|
setRefreshFromBlockHeightNative(height);
|
||||||
|
|
||||||
|
void setRecoveringFromSeed({required bool isRecovery}) =>
|
||||||
|
setRecoveringFromSeedNative(_boolToInt(isRecovery));
|
||||||
|
|
||||||
|
void storeSync() {
|
||||||
|
final pathPointer = ''.toNativeUtf8();
|
||||||
|
storeNative(pathPointer);
|
||||||
|
calloc.free(pathPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPasswordSync(String password) {
|
||||||
|
final passwordPointer = password.toNativeUtf8();
|
||||||
|
final errorMessagePointer = calloc<Utf8Box>();
|
||||||
|
final changed = setPasswordNative(passwordPointer, errorMessagePointer) != 0;
|
||||||
|
calloc.free(passwordPointer);
|
||||||
|
|
||||||
|
if (!changed) {
|
||||||
|
final message = errorMessagePointer.ref.getValue();
|
||||||
|
calloc.free(errorMessagePointer);
|
||||||
|
throw Exception(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
calloc.free(errorMessagePointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void closeCurrentWallet() => closeCurrentWalletNative();
|
||||||
|
|
||||||
|
String getSecretViewKey() =>
|
||||||
|
convertUTF8ToString(pointer: getSecretViewKeyNative());
|
||||||
|
|
||||||
|
String getPublicViewKey() =>
|
||||||
|
convertUTF8ToString(pointer: getPublicViewKeyNative());
|
||||||
|
|
||||||
|
String getSecretSpendKey() =>
|
||||||
|
convertUTF8ToString(pointer: getSecretSpendKeyNative());
|
||||||
|
|
||||||
|
String getPublicSpendKey() =>
|
||||||
|
convertUTF8ToString(pointer: getPublicSpendKeyNative());
|
||||||
|
|
||||||
|
class SyncListener {
|
||||||
|
SyncListener(this.onNewBlock, this.onNewTransaction)
|
||||||
|
: _cachedBlockchainHeight = 0,
|
||||||
|
_lastKnownBlockHeight = 0,
|
||||||
|
_initialSyncHeight = 0;
|
||||||
|
|
||||||
|
|
||||||
|
void Function(int, int, double) onNewBlock;
|
||||||
|
void Function() onNewTransaction;
|
||||||
|
|
||||||
|
Timer? _updateSyncInfoTimer;
|
||||||
|
int _cachedBlockchainHeight;
|
||||||
|
int _lastKnownBlockHeight;
|
||||||
|
int _initialSyncHeight;
|
||||||
|
|
||||||
|
Future<int> getNodeHeightOrUpdate(int baseHeight) async {
|
||||||
|
if (_cachedBlockchainHeight < baseHeight || _cachedBlockchainHeight == 0) {
|
||||||
|
_cachedBlockchainHeight = await getNodeHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _cachedBlockchainHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start() {
|
||||||
|
_cachedBlockchainHeight = 0;
|
||||||
|
_lastKnownBlockHeight = 0;
|
||||||
|
_initialSyncHeight = 0;
|
||||||
|
_updateSyncInfoTimer ??=
|
||||||
|
Timer.periodic(Duration(milliseconds: 1200), (_) async {
|
||||||
|
if (isNewTransactionExist()) {
|
||||||
|
onNewTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
var syncHeight = getSyncingHeight();
|
||||||
|
|
||||||
|
if (syncHeight <= 0) {
|
||||||
|
syncHeight = getCurrentHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_initialSyncHeight <= 0) {
|
||||||
|
_initialSyncHeight = syncHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
final bchHeight = await getNodeHeightOrUpdate(syncHeight);
|
||||||
|
|
||||||
|
if (_lastKnownBlockHeight == syncHeight || syncHeight == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastKnownBlockHeight = syncHeight;
|
||||||
|
final track = bchHeight - _initialSyncHeight;
|
||||||
|
final diff = track - (bchHeight - syncHeight);
|
||||||
|
final ptc = diff <= 0 ? 0.0 : diff / track;
|
||||||
|
final left = bchHeight - syncHeight;
|
||||||
|
|
||||||
|
if (syncHeight < 0 || left < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents;
|
||||||
|
onNewBlock?.call(syncHeight, left, ptc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop() => _updateSyncInfoTimer?.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
SyncListener setListeners(void Function(int, int, double) onNewBlock,
|
||||||
|
void Function() onNewTransaction) {
|
||||||
|
final listener = SyncListener(onNewBlock, onNewTransaction);
|
||||||
|
setListenerNative();
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onStartup() => onStartupNative();
|
||||||
|
|
||||||
|
void _storeSync(Object _) => storeSync();
|
||||||
|
|
||||||
|
bool _setupNodeSync(Map<String, Object?> args) {
|
||||||
|
final address = args['address'] as String;
|
||||||
|
final login = (args['login'] ?? '') as String;
|
||||||
|
final password = (args['password'] ?? '') as String;
|
||||||
|
final useSSL = args['useSSL'] as bool;
|
||||||
|
final isLightWallet = args['isLightWallet'] as bool;
|
||||||
|
|
||||||
|
return setupNodeSync(
|
||||||
|
address: address,
|
||||||
|
login: login,
|
||||||
|
password: password,
|
||||||
|
useSSL: useSSL,
|
||||||
|
isLightWallet: isLightWallet);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isConnected(Object _) => isConnectedSync();
|
||||||
|
|
||||||
|
int _getNodeHeight(Object _) => getNodeHeightSync();
|
||||||
|
|
||||||
|
void startRefresh() => startRefreshSync();
|
||||||
|
|
||||||
|
Future<void> setupNode(
|
||||||
|
{required String address,
|
||||||
|
String? login,
|
||||||
|
String? password,
|
||||||
|
bool useSSL = false,
|
||||||
|
bool isLightWallet = false}) =>
|
||||||
|
compute<Map<String, Object?>, void>(_setupNodeSync, {
|
||||||
|
'address': address,
|
||||||
|
'login': login ,
|
||||||
|
'password': password,
|
||||||
|
'useSSL': useSSL,
|
||||||
|
'isLightWallet': isLightWallet
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> store() => compute<int, void>(_storeSync, 0);
|
||||||
|
|
||||||
|
Future<bool> isConnected() => compute(_isConnected, 0);
|
||||||
|
|
||||||
|
Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
|
||||||
|
|
||||||
|
void rescanBlockchainAsync() => rescanBlockchainAsyncNative();
|
||||||
|
|
||||||
|
String getSubaddressLabel(int accountIndex, int addressIndex) {
|
||||||
|
return convertUTF8ToString(pointer: getSubaddressLabelNative(accountIndex, addressIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future setTrustedDaemon(bool trusted) async => setTrustedDaemonNative(_boolToInt(trusted));
|
||||||
|
|
||||||
|
Future<bool> trustedDaemon() async => trustedDaemonNative() != 0;
|
254
cw_nano/lib/api/wallet_manager.dart
Normal file
254
cw_nano/lib/api/wallet_manager.dart
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:cw_monero/api/convert_utf8_to_string.dart';
|
||||||
|
import 'package:cw_monero/api/signatures.dart';
|
||||||
|
import 'package:cw_monero/api/types.dart';
|
||||||
|
import 'package:cw_monero/api/monero_api.dart';
|
||||||
|
import 'package:cw_monero/api/wallet.dart';
|
||||||
|
import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
|
||||||
|
import 'package:cw_monero/api/exceptions/wallet_creation_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';
|
||||||
|
|
||||||
|
final createWalletNative = moneroApi
|
||||||
|
.lookup<NativeFunction<create_wallet>>('create_wallet')
|
||||||
|
.asFunction<CreateWallet>();
|
||||||
|
|
||||||
|
final restoreWalletFromSeedNative = moneroApi
|
||||||
|
.lookup<NativeFunction<restore_wallet_from_seed>>(
|
||||||
|
'restore_wallet_from_seed')
|
||||||
|
.asFunction<RestoreWalletFromSeed>();
|
||||||
|
|
||||||
|
final restoreWalletFromKeysNative = moneroApi
|
||||||
|
.lookup<NativeFunction<restore_wallet_from_keys>>(
|
||||||
|
'restore_wallet_from_keys')
|
||||||
|
.asFunction<RestoreWalletFromKeys>();
|
||||||
|
|
||||||
|
final isWalletExistNative = moneroApi
|
||||||
|
.lookup<NativeFunction<is_wallet_exist>>('is_wallet_exist')
|
||||||
|
.asFunction<IsWalletExist>();
|
||||||
|
|
||||||
|
final loadWalletNative = moneroApi
|
||||||
|
.lookup<NativeFunction<load_wallet>>('load_wallet')
|
||||||
|
.asFunction<LoadWallet>();
|
||||||
|
|
||||||
|
final errorStringNative = moneroApi
|
||||||
|
.lookup<NativeFunction<error_string>>('error_string')
|
||||||
|
.asFunction<ErrorString>();
|
||||||
|
|
||||||
|
void createWalletSync(
|
||||||
|
{required String path,
|
||||||
|
required String password,
|
||||||
|
required String language,
|
||||||
|
int nettype = 0}) {
|
||||||
|
final pathPointer = path.toNativeUtf8();
|
||||||
|
final passwordPointer = password.toNativeUtf8();
|
||||||
|
final languagePointer = language.toNativeUtf8();
|
||||||
|
final errorMessagePointer = ''.toNativeUtf8();
|
||||||
|
final isWalletCreated = createWalletNative(pathPointer, passwordPointer,
|
||||||
|
languagePointer, nettype, errorMessagePointer) !=
|
||||||
|
0;
|
||||||
|
|
||||||
|
calloc.free(pathPointer);
|
||||||
|
calloc.free(passwordPointer);
|
||||||
|
calloc.free(languagePointer);
|
||||||
|
|
||||||
|
if (!isWalletCreated) {
|
||||||
|
throw WalletCreationException(
|
||||||
|
message: convertUTF8ToString(pointer: errorMessagePointer));
|
||||||
|
}
|
||||||
|
|
||||||
|
// setupNodeSync(address: "node.moneroworld.com:18089");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isWalletExistSync({required String path}) {
|
||||||
|
final pathPointer = path.toNativeUtf8();
|
||||||
|
final isExist = isWalletExistNative(pathPointer) != 0;
|
||||||
|
|
||||||
|
calloc.free(pathPointer);
|
||||||
|
|
||||||
|
return isExist;
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreWalletFromSeedSync(
|
||||||
|
{required String path,
|
||||||
|
required String password,
|
||||||
|
required String seed,
|
||||||
|
int nettype = 0,
|
||||||
|
int restoreHeight = 0}) {
|
||||||
|
final pathPointer = path.toNativeUtf8();
|
||||||
|
final passwordPointer = password.toNativeUtf8();
|
||||||
|
final seedPointer = seed.toNativeUtf8();
|
||||||
|
final errorMessagePointer = ''.toNativeUtf8();
|
||||||
|
final isWalletRestored = restoreWalletFromSeedNative(
|
||||||
|
pathPointer,
|
||||||
|
passwordPointer,
|
||||||
|
seedPointer,
|
||||||
|
nettype,
|
||||||
|
restoreHeight,
|
||||||
|
errorMessagePointer) !=
|
||||||
|
0;
|
||||||
|
|
||||||
|
calloc.free(pathPointer);
|
||||||
|
calloc.free(passwordPointer);
|
||||||
|
calloc.free(seedPointer);
|
||||||
|
|
||||||
|
if (!isWalletRestored) {
|
||||||
|
throw WalletRestoreFromSeedException(
|
||||||
|
message: convertUTF8ToString(pointer: errorMessagePointer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreWalletFromKeysSync(
|
||||||
|
{required String path,
|
||||||
|
required String password,
|
||||||
|
required String language,
|
||||||
|
required String address,
|
||||||
|
required String viewKey,
|
||||||
|
required String spendKey,
|
||||||
|
int nettype = 0,
|
||||||
|
int restoreHeight = 0}) {
|
||||||
|
final pathPointer = path.toNativeUtf8();
|
||||||
|
final passwordPointer = password.toNativeUtf8();
|
||||||
|
final languagePointer = language.toNativeUtf8();
|
||||||
|
final addressPointer = address.toNativeUtf8();
|
||||||
|
final viewKeyPointer = viewKey.toNativeUtf8();
|
||||||
|
final spendKeyPointer = spendKey.toNativeUtf8();
|
||||||
|
final errorMessagePointer = ''.toNativeUtf8();
|
||||||
|
final isWalletRestored = restoreWalletFromKeysNative(
|
||||||
|
pathPointer,
|
||||||
|
passwordPointer,
|
||||||
|
languagePointer,
|
||||||
|
addressPointer,
|
||||||
|
viewKeyPointer,
|
||||||
|
spendKeyPointer,
|
||||||
|
nettype,
|
||||||
|
restoreHeight,
|
||||||
|
errorMessagePointer) !=
|
||||||
|
0;
|
||||||
|
|
||||||
|
calloc.free(pathPointer);
|
||||||
|
calloc.free(passwordPointer);
|
||||||
|
calloc.free(languagePointer);
|
||||||
|
calloc.free(addressPointer);
|
||||||
|
calloc.free(viewKeyPointer);
|
||||||
|
calloc.free(spendKeyPointer);
|
||||||
|
|
||||||
|
if (!isWalletRestored) {
|
||||||
|
throw WalletRestoreFromKeysException(
|
||||||
|
message: convertUTF8ToString(pointer: errorMessagePointer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadWallet({
|
||||||
|
required String path,
|
||||||
|
required String password,
|
||||||
|
int nettype = 0}) {
|
||||||
|
final pathPointer = path.toNativeUtf8();
|
||||||
|
final passwordPointer = password.toNativeUtf8();
|
||||||
|
final loaded = loadWalletNative(pathPointer, passwordPointer, nettype) != 0;
|
||||||
|
calloc.free(pathPointer);
|
||||||
|
calloc.free(passwordPointer);
|
||||||
|
|
||||||
|
if (!loaded) {
|
||||||
|
throw WalletOpeningException(
|
||||||
|
message: convertUTF8ToString(pointer: errorStringNative()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _createWallet(Map<String, dynamic> args) {
|
||||||
|
final path = args['path'] as String;
|
||||||
|
final password = args['password'] as String;
|
||||||
|
final language = args['language'] as String;
|
||||||
|
|
||||||
|
createWalletSync(path: path, password: password, language: language);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _restoreFromSeed(Map<String, dynamic> args) {
|
||||||
|
final path = args['path'] as String;
|
||||||
|
final password = args['password'] as String;
|
||||||
|
final seed = args['seed'] as String;
|
||||||
|
final restoreHeight = args['restoreHeight'] as int;
|
||||||
|
|
||||||
|
restoreWalletFromSeedSync(
|
||||||
|
path: path, password: password, seed: seed, restoreHeight: restoreHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _restoreFromKeys(Map<String, dynamic> args) {
|
||||||
|
final path = args['path'] as String;
|
||||||
|
final password = args['password'] as String;
|
||||||
|
final language = args['language'] as String;
|
||||||
|
final restoreHeight = args['restoreHeight'] as int;
|
||||||
|
final address = args['address'] as String;
|
||||||
|
final viewKey = args['viewKey'] as String;
|
||||||
|
final spendKey = args['spendKey'] as String;
|
||||||
|
|
||||||
|
restoreWalletFromKeysSync(
|
||||||
|
path: path,
|
||||||
|
password: password,
|
||||||
|
language: language,
|
||||||
|
restoreHeight: restoreHeight,
|
||||||
|
address: address,
|
||||||
|
viewKey: viewKey,
|
||||||
|
spendKey: spendKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _openWallet(Map<String, String> args) async =>
|
||||||
|
loadWallet(path: args['path'] as String, password: args['password'] as String);
|
||||||
|
|
||||||
|
bool _isWalletExist(String path) => isWalletExistSync(path: path);
|
||||||
|
|
||||||
|
void openWallet({required String path, required String password, int nettype = 0}) async =>
|
||||||
|
loadWallet(path: path, password: password, nettype: nettype);
|
||||||
|
|
||||||
|
Future<void> openWalletAsync(Map<String, String> args) async =>
|
||||||
|
compute(_openWallet, args);
|
||||||
|
|
||||||
|
Future<void> createWallet(
|
||||||
|
{required String path,
|
||||||
|
required String password,
|
||||||
|
required String language,
|
||||||
|
int nettype = 0}) async =>
|
||||||
|
compute(_createWallet, {
|
||||||
|
'path': path,
|
||||||
|
'password': password,
|
||||||
|
'language': language,
|
||||||
|
'nettype': nettype
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> restoreFromSeed(
|
||||||
|
{required String path,
|
||||||
|
required String password,
|
||||||
|
required String seed,
|
||||||
|
int nettype = 0,
|
||||||
|
int restoreHeight = 0}) async =>
|
||||||
|
compute<Map<String, Object>, void>(_restoreFromSeed, {
|
||||||
|
'path': path,
|
||||||
|
'password': password,
|
||||||
|
'seed': seed,
|
||||||
|
'nettype': nettype,
|
||||||
|
'restoreHeight': restoreHeight
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> restoreFromKeys(
|
||||||
|
{required String path,
|
||||||
|
required String password,
|
||||||
|
required String language,
|
||||||
|
required String address,
|
||||||
|
required String viewKey,
|
||||||
|
required String spendKey,
|
||||||
|
int nettype = 0,
|
||||||
|
int restoreHeight = 0}) async =>
|
||||||
|
compute<Map<String, Object>, void>(_restoreFromKeys, {
|
||||||
|
'path': path,
|
||||||
|
'password': password,
|
||||||
|
'language': language,
|
||||||
|
'address': address,
|
||||||
|
'viewKey': viewKey,
|
||||||
|
'spendKey': spendKey,
|
||||||
|
'nettype': nettype,
|
||||||
|
'restoreHeight': restoreHeight
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<bool> isWalletExist({required String path}) => compute(_isWalletExist, path);
|
82
cw_nano/lib/nano_account_list.dart
Normal file
82
cw_nano/lib/nano_account_list.dart
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
import 'package:cw_core/monero_amount_format.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cw_core/account.dart';
|
||||||
|
import 'package:cw_nano/api/account_list.dart' as account_list;
|
||||||
|
import 'package:cw_nano/api/wallet.dart' as monero_wallet;
|
||||||
|
|
||||||
|
part 'nano_account_list.g.dart';
|
||||||
|
|
||||||
|
class NanoAccountList = NanoAccountListBase with _$NanoAccountList;
|
||||||
|
|
||||||
|
abstract class NanoAccountListBase with Store {
|
||||||
|
NanoAccountListBase()
|
||||||
|
: accounts = ObservableList<Account>(),
|
||||||
|
_isRefreshing = false,
|
||||||
|
_isUpdating = false {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
@observable
|
||||||
|
ObservableList<Account> accounts;
|
||||||
|
bool _isRefreshing;
|
||||||
|
bool _isUpdating;
|
||||||
|
|
||||||
|
void update() async {
|
||||||
|
if (_isUpdating) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
_isUpdating = true;
|
||||||
|
refresh();
|
||||||
|
final accounts = getAll();
|
||||||
|
|
||||||
|
if (accounts.isNotEmpty) {
|
||||||
|
this.accounts.clear();
|
||||||
|
this.accounts.addAll(accounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
_isUpdating = false;
|
||||||
|
} catch (e) {
|
||||||
|
_isUpdating = false;
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Account> getAll() => account_list.getAllAccount().map((accountRow) {
|
||||||
|
final accountIndex = accountRow.getId();
|
||||||
|
final balance = monero_wallet.getFullBalance(accountIndex: accountIndex);
|
||||||
|
|
||||||
|
return Account(
|
||||||
|
id: accountRow.getId(),
|
||||||
|
label: accountRow.getLabel(),
|
||||||
|
balance: moneroAmountToString(amount: balance),
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
Future<void> addAccount({required String label}) async {
|
||||||
|
await account_list.addAccount(label: label);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setLabelAccount({required int accountIndex, required String label}) async {
|
||||||
|
await account_list.setLabelForAccount(accountIndex: accountIndex, label: label);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh() {
|
||||||
|
if (_isRefreshing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
_isRefreshing = true;
|
||||||
|
account_list.refreshAccounts();
|
||||||
|
_isRefreshing = false;
|
||||||
|
} catch (e) {
|
||||||
|
_isRefreshing = false;
|
||||||
|
print(e);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,7 +24,6 @@ class NanoBalance extends Balance {
|
||||||
// super(moneroParseAmount(amount: formattedReceivableBalance),
|
// super(moneroParseAmount(amount: formattedReceivableBalance),
|
||||||
// moneroParseAmount(amount: formattedCurrentBalance));
|
// moneroParseAmount(amount: formattedCurrentBalance));
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedAvailableBalance => "error";
|
String get formattedAvailableBalance => "error";
|
||||||
|
|
||||||
|
|
28
cw_nano/lib/nano_transaction_history.dart
Normal file
28
cw_nano/lib/nano_transaction_history.dart
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import 'dart:core';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cw_core/transaction_history.dart';
|
||||||
|
import 'package:cw_nano/nano_transaction_info.dart';
|
||||||
|
|
||||||
|
part 'nano_transaction_history.g.dart';
|
||||||
|
|
||||||
|
class NanoTransactionHistory = NanoTransactionHistoryBase
|
||||||
|
with _$NanoTransactionHistory;
|
||||||
|
|
||||||
|
abstract class NanoTransactionHistoryBase
|
||||||
|
extends TransactionHistoryBase<NanoTransactionInfo> with Store {
|
||||||
|
NanoTransactionHistoryBase() {
|
||||||
|
transactions = ObservableMap<String, NanoTransactionInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> save() async {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void addOne(NanoTransactionInfo transaction) =>
|
||||||
|
transactions[transaction.id] = transaction;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void addMany(Map<String, MoneroTransactionInfo> transactions) =>
|
||||||
|
this.transactions.addAll(transactions);
|
||||||
|
|
||||||
|
}
|
|
@ -3,23 +3,11 @@ import 'dart:io';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/transaction_priority.dart';
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
import 'package:cw_core/monero_amount_format.dart';
|
import 'package:cw_core/monero_amount_format.dart';
|
||||||
import 'package:cw_monero/monero_transaction_creation_exception.dart';
|
|
||||||
import 'package:cw_monero/monero_transaction_info.dart';
|
|
||||||
import 'package:cw_monero/monero_wallet_addresses.dart';
|
|
||||||
import 'package:cw_core/monero_wallet_utils.dart';
|
import 'package:cw_core/monero_wallet_utils.dart';
|
||||||
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
import 'package:cw_nano/nano_balance.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cw_monero/api/transaction_history.dart'
|
|
||||||
as monero_transaction_history;
|
|
||||||
import 'package:cw_monero/api/wallet.dart';
|
|
||||||
import 'package:cw_monero/api/wallet.dart' as monero_wallet;
|
|
||||||
import 'package:cw_monero/api/transaction_history.dart' as transaction_history;
|
|
||||||
import 'package:cw_monero/api/monero_output.dart';
|
|
||||||
import 'package:cw_monero/monero_transaction_creation_credentials.dart';
|
|
||||||
import 'package:cw_monero/pending_monero_transaction.dart';
|
|
||||||
import 'package:cw_core/monero_wallet_keys.dart';
|
import 'package:cw_core/monero_wallet_keys.dart';
|
||||||
import 'package:cw_core/monero_balance.dart';
|
import 'package:cw_core/monero_balance.dart';
|
||||||
import 'package:cw_monero/monero_transaction_history.dart';
|
|
||||||
import 'package:cw_core/account.dart';
|
import 'package:cw_core/account.dart';
|
||||||
import 'package:cw_core/pending_transaction.dart';
|
import 'package:cw_core/pending_transaction.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
@ -35,13 +23,13 @@ const moneroBlockSize = 1000;
|
||||||
|
|
||||||
class NanoWallet = NanoWalletBase with _$NanoWallet;
|
class NanoWallet = NanoWalletBase with _$NanoWallet;
|
||||||
|
|
||||||
abstract class NanoWalletBase extends WalletBase<MoneroBalance,
|
abstract class NanoWalletBase
|
||||||
MoneroTransactionHistory, MoneroTransactionInfo> with Store {
|
extends WalletBase<NanoBalance, NanoTransactionHistory, NanoTransactionInfo> with Store {
|
||||||
NanoWalletBase({required WalletInfo walletInfo})
|
NanoWalletBase({required WalletInfo walletInfo})
|
||||||
: balance = ObservableMap<CryptoCurrency, MoneroBalance>.of({
|
: balance = ObservableMap<CryptoCurrency, NanoBalance>.of({
|
||||||
CryptoCurrency.xmr: MoneroBalance(
|
CryptoCurrency.nano: NanoBalance(
|
||||||
fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
|
currentBalance: nano_wallet.getFullBalance(accountIndex: 0),
|
||||||
unlockedBalance: monero_wallet.getFullBalance(accountIndex: 0))
|
receivableBalance: nano_wallet.getFullBalance(accountIndex: 0))
|
||||||
}),
|
}),
|
||||||
_isTransactionUpdating = false,
|
_isTransactionUpdating = false,
|
||||||
_hasSyncAfterStartup = false,
|
_hasSyncAfterStartup = false,
|
||||||
|
@ -49,18 +37,15 @@ abstract class NanoWalletBase extends WalletBase<MoneroBalance,
|
||||||
syncStatus = NotConnectedSyncStatus(),
|
syncStatus = NotConnectedSyncStatus(),
|
||||||
super(walletInfo) {
|
super(walletInfo) {
|
||||||
transactionHistory = MoneroTransactionHistory();
|
transactionHistory = MoneroTransactionHistory();
|
||||||
_onAccountChangeReaction = reaction((_) => walletAddresses.account,
|
_onAccountChangeReaction = reaction((_) => walletAddresses.account, (Account? account) {
|
||||||
(Account? account) {
|
|
||||||
if (account == null) {
|
if (account == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(
|
balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(<CryptoCurrency, MoneroBalance>{
|
||||||
<CryptoCurrency, MoneroBalance>{
|
|
||||||
currency: MoneroBalance(
|
currency: MoneroBalance(
|
||||||
fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
|
fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
|
||||||
unlockedBalance:
|
unlockedBalance: monero_wallet.getUnlockedBalance(accountIndex: account.id))
|
||||||
monero_wallet.getUnlockedBalance(accountIndex: account.id))
|
|
||||||
});
|
});
|
||||||
walletAddresses.updateSubaddressList(accountIndex: account.id);
|
walletAddresses.updateSubaddressList(accountIndex: account.id);
|
||||||
});
|
});
|
||||||
|
@ -97,11 +82,11 @@ abstract class NanoWalletBase extends WalletBase<MoneroBalance,
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
await walletAddresses.init();
|
await walletAddresses.init();
|
||||||
balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(
|
balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(<CryptoCurrency, MoneroBalance>{
|
||||||
<CryptoCurrency, MoneroBalance>{
|
|
||||||
currency: MoneroBalance(
|
currency: MoneroBalance(
|
||||||
fullBalance: monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id),
|
fullBalance: monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id),
|
||||||
unlockedBalance: monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id))
|
unlockedBalance:
|
||||||
|
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id))
|
||||||
});
|
});
|
||||||
_setListeners();
|
_setListeners();
|
||||||
await updateTransactions();
|
await updateTransactions();
|
||||||
|
@ -110,8 +95,7 @@ abstract class NanoWalletBase extends WalletBase<MoneroBalance,
|
||||||
monero_wallet.setRecoveringFromSeed(isRecovery: walletInfo.isRecovery);
|
monero_wallet.setRecoveringFromSeed(isRecovery: walletInfo.isRecovery);
|
||||||
|
|
||||||
if (monero_wallet.getCurrentHeight() <= 1) {
|
if (monero_wallet.getCurrentHeight() <= 1) {
|
||||||
monero_wallet.setRefreshFromBlockHeight(
|
monero_wallet.setRefreshFromBlockHeight(height: walletInfo.restoreHeight);
|
||||||
height: walletInfo.restoreHeight);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,6 +103,7 @@ abstract class NanoWalletBase extends WalletBase<MoneroBalance,
|
||||||
// Duration(seconds: _autoSaveInterval),
|
// Duration(seconds: _autoSaveInterval),
|
||||||
// (_) async => await save());
|
// (_) async => await save());
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void>? updateBalance() => null;
|
Future<void>? updateBalance() => null;
|
||||||
|
|
||||||
|
@ -134,9 +119,7 @@ abstract class NanoWalletBase extends WalletBase<MoneroBalance,
|
||||||
try {
|
try {
|
||||||
syncStatus = ConnectingSyncStatus();
|
syncStatus = ConnectingSyncStatus();
|
||||||
await monero_wallet.setupNode(
|
await monero_wallet.setupNode(
|
||||||
address: node.uri.toString(),
|
address: node.uri.toString(), useSSL: node.isSSL, isLightWallet: false);
|
||||||
useSSL: node.isSSL,
|
|
||||||
isLightWallet: false);
|
|
||||||
|
|
||||||
monero_wallet.setTrustedDaemon(node.trusted);
|
monero_wallet.setTrustedDaemon(node.trusted);
|
||||||
syncStatus = ConnectedSyncStatus();
|
syncStatus = ConnectedSyncStatus();
|
||||||
|
@ -166,96 +149,14 @@ abstract class NanoWalletBase extends WalletBase<MoneroBalance,
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||||
final _credentials = credentials as MoneroTransactionCreationCredentials;
|
// final _credentials = credentials as MoneroTransactionCreationCredentials;
|
||||||
final outputs = _credentials.outputs;
|
// return null;
|
||||||
final hasMultiDestination = outputs.length > 1;
|
throw UnimplementedError();
|
||||||
final unlockedBalance =
|
|
||||||
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
|
|
||||||
|
|
||||||
PendingTransactionDescription pendingTransactionDescription;
|
|
||||||
|
|
||||||
if (!(syncStatus is SyncedSyncStatus)) {
|
|
||||||
throw MoneroTransactionCreationException('The wallet is not synced.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasMultiDestination) {
|
|
||||||
if (outputs.any((item) => item.sendAll
|
|
||||||
|| (item.formattedCryptoAmount ?? 0) <= 0)) {
|
|
||||||
throw MoneroTransactionCreationException('You do not have enough XMR to send this amount.');
|
|
||||||
}
|
|
||||||
|
|
||||||
final int totalAmount = outputs.fold(0, (acc, value) =>
|
|
||||||
acc + (value.formattedCryptoAmount ?? 0));
|
|
||||||
|
|
||||||
if (unlockedBalance < totalAmount) {
|
|
||||||
throw MoneroTransactionCreationException('You do not have enough XMR to send this amount.');
|
|
||||||
}
|
|
||||||
|
|
||||||
final moneroOutputs = outputs.map((output) {
|
|
||||||
final outputAddress = output.isParsedAddress
|
|
||||||
? output.extractedAddress
|
|
||||||
: output.address;
|
|
||||||
|
|
||||||
return MoneroOutput(
|
|
||||||
address: outputAddress!,
|
|
||||||
amount: output.cryptoAmount!.replaceAll(',', '.'));
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
pendingTransactionDescription =
|
|
||||||
await transaction_history.createTransactionMultDest(
|
|
||||||
outputs: moneroOutputs,
|
|
||||||
priorityRaw: _credentials.priority.serialize(),
|
|
||||||
accountIndex: walletAddresses.account!.id);
|
|
||||||
} else {
|
|
||||||
final output = outputs.first;
|
|
||||||
final address = output.isParsedAddress
|
|
||||||
? output.extractedAddress
|
|
||||||
: output.address;
|
|
||||||
final amount = output.sendAll
|
|
||||||
? null
|
|
||||||
: output.cryptoAmount!.replaceAll(',', '.');
|
|
||||||
final formattedAmount = output.sendAll
|
|
||||||
? null
|
|
||||||
: output.formattedCryptoAmount;
|
|
||||||
|
|
||||||
if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
|
|
||||||
(formattedAmount == null && unlockedBalance <= 0)) {
|
|
||||||
final formattedBalance = moneroAmountToString(amount: unlockedBalance);
|
|
||||||
|
|
||||||
throw MoneroTransactionCreationException(
|
|
||||||
'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
|
|
||||||
}
|
|
||||||
|
|
||||||
pendingTransactionDescription =
|
|
||||||
await transaction_history.createTransaction(
|
|
||||||
address: address!,
|
|
||||||
amount: amount,
|
|
||||||
priorityRaw: _credentials.priority.serialize(),
|
|
||||||
accountIndex: walletAddresses.account!.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return PendingMoneroTransaction(pendingTransactionDescription);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int calculateEstimatedFee(TransactionPriority priority, int? amount) {
|
int calculateEstimatedFee(TransactionPriority priority, int? amount) {
|
||||||
// FIXME: hardcoded value;
|
// FIXME: hardcoded value;
|
||||||
|
|
||||||
if (priority is MoneroTransactionPriority) {
|
|
||||||
switch (priority) {
|
|
||||||
case MoneroTransactionPriority.slow:
|
|
||||||
return 24590000;
|
|
||||||
case MoneroTransactionPriority.automatic:
|
|
||||||
return 123050000;
|
|
||||||
case MoneroTransactionPriority.medium:
|
|
||||||
return 245029999;
|
|
||||||
case MoneroTransactionPriority.fast:
|
|
||||||
return 614530000;
|
|
||||||
case MoneroTransactionPriority.fastest:
|
|
||||||
return 26021600000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,10 +173,8 @@ abstract class NanoWalletBase extends WalletBase<MoneroBalance,
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// -- rename the waller folder --
|
// -- rename the waller folder --
|
||||||
final currentWalletDir =
|
final currentWalletDir = Directory(await pathForWalletDir(name: name, type: type));
|
||||||
Directory(await pathForWalletDir(name: name, type: type));
|
final newWalletDirPath = await pathForWalletDir(name: newWalletName, type: type);
|
||||||
final newWalletDirPath =
|
|
||||||
await pathForWalletDir(name: newWalletName, type: type);
|
|
||||||
await currentWalletDir.rename(newWalletDirPath);
|
await currentWalletDir.rename(newWalletDirPath);
|
||||||
|
|
||||||
// -- use new waller folder to rename files with old names still --
|
// -- use new waller folder to rename files with old names still --
|
||||||
|
@ -285,8 +184,7 @@ abstract class NanoWalletBase extends WalletBase<MoneroBalance,
|
||||||
final currentKeysFile = File('$renamedWalletPath.keys');
|
final currentKeysFile = File('$renamedWalletPath.keys');
|
||||||
final currentAddressListFile = File('$renamedWalletPath.address.txt');
|
final currentAddressListFile = File('$renamedWalletPath.address.txt');
|
||||||
|
|
||||||
final newWalletPath =
|
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
|
||||||
await pathForWallet(name: newWalletName, type: type);
|
|
||||||
|
|
||||||
if (currentCacheFile.existsSync()) {
|
if (currentCacheFile.existsSync()) {
|
||||||
await currentCacheFile.rename(newWalletPath);
|
await currentCacheFile.rename(newWalletPath);
|
||||||
|
@ -304,8 +202,7 @@ abstract class NanoWalletBase extends WalletBase<MoneroBalance,
|
||||||
final currentKeysFile = File('$currentWalletPath.keys');
|
final currentKeysFile = File('$currentWalletPath.keys');
|
||||||
final currentAddressListFile = File('$currentWalletPath.address.txt');
|
final currentAddressListFile = File('$currentWalletPath.address.txt');
|
||||||
|
|
||||||
final newWalletPath =
|
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
|
||||||
await pathForWallet(name: newWalletName, type: type);
|
|
||||||
|
|
||||||
// Copies current wallet files into new wallet name's dir and files
|
// Copies current wallet files into new wallet name's dir and files
|
||||||
if (currentCacheFile.existsSync()) {
|
if (currentCacheFile.existsSync()) {
|
||||||
|
@ -352,15 +249,13 @@ abstract class NanoWalletBase extends WalletBase<MoneroBalance,
|
||||||
}
|
}
|
||||||
|
|
||||||
String getTransactionAddress(int accountIndex, int addressIndex) =>
|
String getTransactionAddress(int accountIndex, int addressIndex) =>
|
||||||
monero_wallet.getAddress(
|
monero_wallet.getAddress(accountIndex: accountIndex, addressIndex: addressIndex);
|
||||||
accountIndex: accountIndex,
|
|
||||||
addressIndex: addressIndex);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, MoneroTransactionInfo>> fetchTransactions() async {
|
Future<Map<String, MoneroTransactionInfo>> fetchTransactions() async {
|
||||||
monero_transaction_history.refreshTransactions();
|
monero_transaction_history.refreshTransactions();
|
||||||
return _getAllTransactions(null).fold<Map<String, MoneroTransactionInfo>>(
|
return _getAllTransactions(null)
|
||||||
<String, MoneroTransactionInfo>{},
|
.fold<Map<String, MoneroTransactionInfo>>(<String, MoneroTransactionInfo>{},
|
||||||
(Map<String, MoneroTransactionInfo> acc, MoneroTransactionInfo tx) {
|
(Map<String, MoneroTransactionInfo> acc, MoneroTransactionInfo tx) {
|
||||||
acc[tx.id] = tx;
|
acc[tx.id] = tx;
|
||||||
return acc;
|
return acc;
|
||||||
|
@ -388,8 +283,7 @@ abstract class NanoWalletBase extends WalletBase<MoneroBalance,
|
||||||
return monero_wallet.getSubaddressLabel(accountIndex, addressIndex);
|
return monero_wallet.getSubaddressLabel(accountIndex, addressIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<MoneroTransactionInfo> _getAllTransactions(dynamic _) =>
|
List<MoneroTransactionInfo> _getAllTransactions(dynamic _) => monero_transaction_history
|
||||||
monero_transaction_history
|
|
||||||
.getAllTransations()
|
.getAllTransations()
|
||||||
.map((row) => MoneroTransactionInfo.fromRow(row))
|
.map((row) => MoneroTransactionInfo.fromRow(row))
|
||||||
.toList();
|
.toList();
|
||||||
|
@ -414,8 +308,7 @@ abstract class NanoWalletBase extends WalletBase<MoneroBalance,
|
||||||
}
|
}
|
||||||
|
|
||||||
int _getHeightDistance(DateTime date) {
|
int _getHeightDistance(DateTime date) {
|
||||||
final distance =
|
final distance = DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch;
|
||||||
DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch;
|
|
||||||
final daysTmp = (distance / 86400).round();
|
final daysTmp = (distance / 86400).round();
|
||||||
final days = daysTmp < 1 ? 1 : daysTmp;
|
final days = daysTmp < 1 ? 1 : daysTmp;
|
||||||
|
|
||||||
|
@ -439,16 +332,13 @@ abstract class NanoWalletBase extends WalletBase<MoneroBalance,
|
||||||
|
|
||||||
if (balance[currency]!.fullBalance != fullBalance ||
|
if (balance[currency]!.fullBalance != fullBalance ||
|
||||||
balance[currency]!.unlockedBalance != unlockedBalance) {
|
balance[currency]!.unlockedBalance != unlockedBalance) {
|
||||||
balance[currency] = MoneroBalance(
|
balance[currency] = MoneroBalance(fullBalance: fullBalance, unlockedBalance: unlockedBalance);
|
||||||
fullBalance: fullBalance, unlockedBalance: unlockedBalance);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _askForUpdateTransactionHistory() async =>
|
Future<void> _askForUpdateTransactionHistory() async => await updateTransactions();
|
||||||
await updateTransactions();
|
|
||||||
|
|
||||||
int _getFullBalance() =>
|
int _getFullBalance() => monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id);
|
||||||
monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id);
|
|
||||||
|
|
||||||
int _getUnlockedBalance() =>
|
int _getUnlockedBalance() =>
|
||||||
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
|
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
|
||||||
|
|
45
cw_nano/lib/nano_wallet_addresses.dart
Normal file
45
cw_nano/lib/nano_wallet_addresses.dart
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import 'package:cw_core/wallet_addresses.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_core/account.dart';
|
||||||
|
import 'package:cw_nano/nano_account_list.dart';
|
||||||
|
import 'package:cw_core/subaddress.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
part 'monero_wallet_addresses.g.dart';
|
||||||
|
|
||||||
|
class NanoWalletAddresses = NanoWalletAddressesBase
|
||||||
|
with _$NanoWalletAddresses;
|
||||||
|
|
||||||
|
abstract class NanoWalletAddressesBase extends WalletAddresses with Store {
|
||||||
|
NanoWalletAddressesBase(WalletInfo walletInfo)
|
||||||
|
: accountList = NanoAccountList(),
|
||||||
|
address = '',
|
||||||
|
super(walletInfo);
|
||||||
|
|
||||||
|
@override
|
||||||
|
@observable
|
||||||
|
String address;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
Account? account;
|
||||||
|
|
||||||
|
|
||||||
|
NanoAccountList accountList;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> init() async {
|
||||||
|
accountList.update();
|
||||||
|
account = accountList.accounts.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool validate() {
|
||||||
|
accountList.update();
|
||||||
|
final accountListLength = accountList.accounts.length ?? 0;
|
||||||
|
|
||||||
|
if (accountListLength <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
26
cw_nano/lib/nano_wallet_creation_credentials.dart
Normal file
26
cw_nano/lib/nano_wallet_creation_credentials.dart
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import 'package:cw_core/wallet_credentials.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
|
||||||
|
class NanoNewWalletCredentials extends WalletCredentials {
|
||||||
|
NanoNewWalletCredentials({required String name, WalletInfo? walletInfo})
|
||||||
|
: super(name: name, walletInfo: walletInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
class NanoRestoreWalletFromSeedCredentials extends WalletCredentials {
|
||||||
|
NanoRestoreWalletFromSeedCredentials(
|
||||||
|
{required String name,
|
||||||
|
required String password,
|
||||||
|
required this.mnemonic,
|
||||||
|
WalletInfo? walletInfo})
|
||||||
|
: super(name: name, password: password, walletInfo: walletInfo);
|
||||||
|
|
||||||
|
final String mnemonic;
|
||||||
|
}
|
||||||
|
|
||||||
|
class NanoRestoreWalletFromWIFCredentials extends WalletCredentials {
|
||||||
|
NanoRestoreWalletFromWIFCredentials(
|
||||||
|
{required String name, required String password, required this.wif, WalletInfo? walletInfo})
|
||||||
|
: super(name: name, password: password, walletInfo: walletInfo);
|
||||||
|
|
||||||
|
final String wif;
|
||||||
|
}
|
103
cw_nano/lib/nano_wallet_service.dart
Normal file
103
cw_nano/lib/nano_wallet_service.dart
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_core/wallet_service.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
// import 'package:cw_nano/nano_mnemonics.dart';
|
||||||
|
import 'package:cw_nano/nano_wallet.dart';
|
||||||
|
import 'package:cw_nano/nano_wallet_creation_credentials.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||||
|
NanoRestoreWalletFromSeedCredentials, NanoRestoreWalletFromWIFCredentials> {
|
||||||
|
NanoWalletService(this.walletInfoSource);
|
||||||
|
|
||||||
|
final Box<WalletInfo> walletInfoSource;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<NanoWallet> create(NanoNewWalletCredentials credentials) async {
|
||||||
|
final mnemonic = bip39.generateMnemonic();
|
||||||
|
final wallet = NanoWallet(
|
||||||
|
walletInfo: credentials.walletInfo!,
|
||||||
|
mnemonic: mnemonic,
|
||||||
|
password: credentials.password!,
|
||||||
|
);
|
||||||
|
|
||||||
|
await wallet.init();
|
||||||
|
await wallet.save();
|
||||||
|
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
WalletType getType() => WalletType.ethereum;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> isWalletExit(String name) async =>
|
||||||
|
File(await pathForWallet(name: name, type: getType())).existsSync();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<NanoWallet> openWallet(String name, String password) async {
|
||||||
|
final walletInfo =
|
||||||
|
walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
|
||||||
|
final wallet = await NanoWalletBase.open(
|
||||||
|
name: name,
|
||||||
|
password: password,
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
);
|
||||||
|
|
||||||
|
await wallet.init();
|
||||||
|
await wallet.save();
|
||||||
|
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> remove(String wallet) async =>
|
||||||
|
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<NanoWallet> restoreFromKeys(credentials) {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<NanoWallet> restoreFromSeed(
|
||||||
|
NanoRestoreWalletFromSeedCredentials credentials) async {
|
||||||
|
// if (!bip39.validateMnemonic(credentials.mnemonic)) {
|
||||||
|
// throw EthereumMnemonicIsIncorrectException();
|
||||||
|
// }
|
||||||
|
|
||||||
|
final wallet = await NanoWallet(
|
||||||
|
// password: credentials.password!,
|
||||||
|
// mnemonic: credentials.mnemonic,
|
||||||
|
walletInfo: credentials.walletInfo!,
|
||||||
|
);
|
||||||
|
|
||||||
|
await wallet.init();
|
||||||
|
await wallet.save();
|
||||||
|
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> rename(String currentName, String password, String newName) async {
|
||||||
|
final currentWalletInfo = walletInfoSource.values
|
||||||
|
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||||
|
final currentWallet = await NanoWalletBase.open(
|
||||||
|
password: password, name: currentName, walletInfo: currentWalletInfo);
|
||||||
|
|
||||||
|
await currentWallet.renameWalletFiles(newName);
|
||||||
|
|
||||||
|
final newWalletInfo = currentWalletInfo;
|
||||||
|
newWalletInfo.id = WalletBase.idFor(newName, getType());
|
||||||
|
newWalletInfo.name = newName;
|
||||||
|
|
||||||
|
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,121 +1,105 @@
|
||||||
part of 'nano.dart';
|
part of 'nano.dart';
|
||||||
|
|
||||||
|
|
||||||
|
// class CWMoneroAccountList extends MoneroAccountList {
|
||||||
|
// CWMoneroAccountList(this._wallet);
|
||||||
|
// final Object _wallet;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// @computed
|
||||||
|
// ObservableList<Account> get accounts {
|
||||||
|
// final moneroWallet = _wallet as MoneroWallet;
|
||||||
|
// final accounts = moneroWallet.walletAddresses.accountList
|
||||||
|
// .accounts
|
||||||
|
// .map((acc) => Account(id: acc.id, label: acc.label, balance: acc.balance))
|
||||||
|
// .toList();
|
||||||
|
// return ObservableList<Account>.of(accounts);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void update(Object wallet) {
|
||||||
|
// final moneroWallet = wallet as MoneroWallet;
|
||||||
|
// moneroWallet.walletAddresses.accountList.update();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void refresh(Object wallet) {
|
||||||
|
// final moneroWallet = wallet as MoneroWallet;
|
||||||
|
// moneroWallet.walletAddresses.accountList.refresh();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// List<Account> getAll(Object wallet) {
|
||||||
|
// final moneroWallet = wallet as MoneroWallet;
|
||||||
|
// return moneroWallet.walletAddresses.accountList
|
||||||
|
// .getAll()
|
||||||
|
// .map((acc) => Account(id: acc.id, label: acc.label, balance: acc.balance))
|
||||||
|
// .toList();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Future<void> addAccount(Object wallet, {required String label}) async {
|
||||||
|
// final moneroWallet = wallet as MoneroWallet;
|
||||||
|
// await moneroWallet.walletAddresses.accountList.addAccount(label: label);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Future<void> setLabelAccount(Object wallet, {required int accountIndex, required String label}) async {
|
||||||
|
// final moneroWallet = wallet as MoneroWallet;
|
||||||
|
// await moneroWallet.walletAddresses.accountList
|
||||||
|
// .setLabelAccount(
|
||||||
|
// accountIndex: accountIndex,
|
||||||
|
// label: label);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
class CWNano extends Nano {
|
class CWNano extends Nano {
|
||||||
@override
|
|
||||||
List<String> getNanoWordList(String language) => EthereumMnemonics.englishWordlist;
|
|
||||||
|
|
||||||
WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource) =>
|
// @override
|
||||||
EthereumWalletService(walletInfoSource);
|
// NanoAccountList getAccountList(Object wallet) {
|
||||||
|
// return CWNanoAccountList(wallet);
|
||||||
|
// }
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletCredentials createEthereumNewWalletCredentials({
|
List<String> getNanoWordList(String language) {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource) {
|
||||||
|
return NanoWalletService(walletInfoSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// WalletCredentials createNanoNewWalletCredentials({
|
||||||
|
// required String name,
|
||||||
|
// WalletInfo? walletInfo,
|
||||||
|
// }) =>
|
||||||
|
// NanoNewWalletCredentials(name: name, walletInfo: walletInfo);
|
||||||
|
|
||||||
|
@override
|
||||||
|
WalletCredentials createNanoNewWalletCredentials({
|
||||||
required String name,
|
required String name,
|
||||||
WalletInfo? walletInfo,
|
required String language,
|
||||||
}) =>
|
String? password,
|
||||||
EthereumNewWalletCredentials(name: name, walletInfo: walletInfo);
|
}) {
|
||||||
|
return NanoNewWalletCredentials(name: name, password: password, language: language);
|
||||||
@override
|
|
||||||
WalletCredentials createEthereumRestoreWalletFromSeedCredentials({
|
|
||||||
required String name,
|
|
||||||
required String mnemonic,
|
|
||||||
required String password,
|
|
||||||
}) =>
|
|
||||||
EthereumRestoreWalletFromSeedCredentials(name: name, password: password, mnemonic: mnemonic);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getAddress(WalletBase wallet) => (wallet as EthereumWallet).walletAddresses.address;
|
|
||||||
|
|
||||||
@override
|
|
||||||
TransactionPriority getDefaultTransactionPriority() => EthereumTransactionPriority.medium;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<TransactionPriority> getTransactionPriorities() => EthereumTransactionPriority.all;
|
|
||||||
|
|
||||||
@override
|
|
||||||
TransactionPriority deserializeEthereumTransactionPriority(int raw) =>
|
|
||||||
EthereumTransactionPriority.deserialize(raw: raw);
|
|
||||||
|
|
||||||
@override
|
|
||||||
int getEstimatedFee(Object wallet, TransactionPriority priority) {
|
|
||||||
final ethereumWallet = wallet as EthereumWallet;
|
|
||||||
return ethereumWallet.feeRate(priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object createEthereumTransactionCredentials(
|
|
||||||
List<Output> outputs, {
|
|
||||||
required TransactionPriority priority,
|
|
||||||
required CryptoCurrency currency,
|
|
||||||
int? feeRate,
|
|
||||||
}) =>
|
|
||||||
EthereumTransactionCredentials(
|
|
||||||
outputs
|
|
||||||
.map((out) => OutputInfo(
|
|
||||||
fiatAmount: out.fiatAmount,
|
|
||||||
cryptoAmount: out.cryptoAmount,
|
|
||||||
address: out.address,
|
|
||||||
note: out.note,
|
|
||||||
sendAll: out.sendAll,
|
|
||||||
extractedAddress: out.extractedAddress,
|
|
||||||
isParsedAddress: out.isParsedAddress,
|
|
||||||
formattedCryptoAmount: out.formattedCryptoAmount))
|
|
||||||
.toList(),
|
|
||||||
priority: priority as EthereumTransactionPriority,
|
|
||||||
currency: currency,
|
|
||||||
feeRate: feeRate,
|
|
||||||
);
|
|
||||||
|
|
||||||
Object createEthereumTransactionCredentialsRaw(
|
|
||||||
List<OutputInfo> outputs, {
|
|
||||||
TransactionPriority? priority,
|
|
||||||
required CryptoCurrency currency,
|
|
||||||
required int feeRate,
|
|
||||||
}) =>
|
|
||||||
EthereumTransactionCredentials(
|
|
||||||
outputs,
|
|
||||||
priority: priority as EthereumTransactionPriority?,
|
|
||||||
currency: currency,
|
|
||||||
feeRate: feeRate,
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
|
||||||
int formatterEthereumParseAmount(String amount) => EthereumFormatter.parseEthereumAmount(amount);
|
|
||||||
|
|
||||||
@override
|
|
||||||
double formatterEthereumAmountToDouble({required TransactionInfo transaction}) {
|
|
||||||
transaction as EthereumTransactionInfo;
|
|
||||||
return cryptoAmountToDouble(
|
|
||||||
amount: transaction.amount, divider: BigInt.from(10).pow(transaction.exponent).toInt());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Erc20Token> getERC20Currencies(WalletBase wallet) {
|
TransactionHistoryBase getTransactionHistory(Object wallet) {
|
||||||
final ethereumWallet = wallet as EthereumWallet;
|
// final moneroWallet = wallet as MoneroWallet;
|
||||||
return ethereumWallet.erc20Currencies;
|
// return moneroWallet.transactionHistory;
|
||||||
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> addErc20Token(WalletBase wallet, Erc20Token token) async =>
|
void onStartup() {
|
||||||
await (wallet as EthereumWallet).addErc20Token(token);
|
// monero_wallet_api.onStartup();
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> deleteErc20Token(WalletBase wallet, Erc20Token token) async =>
|
|
||||||
await (wallet as EthereumWallet).deleteErc20Token(token);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async {
|
|
||||||
final ethereumWallet = wallet as EthereumWallet;
|
|
||||||
return await ethereumWallet.getErc20Token(contractAddress);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction) {
|
List<String> getMoneroWordList(String language) {
|
||||||
transaction as EthereumTransactionInfo;
|
throw UnimplementedError();
|
||||||
if (transaction.tokenSymbol == CryptoCurrency.eth.title) {
|
|
||||||
return CryptoCurrency.eth;
|
|
||||||
}
|
|
||||||
|
|
||||||
wallet as EthereumWallet;
|
|
||||||
return wallet.erc20Currencies
|
|
||||||
.firstWhere((element) => transaction.tokenSymbol == element.symbol);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,61 +1,59 @@
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cake_wallet/view_model/send/output.dart';
|
|
||||||
import 'package:cw_core/crypto_amount_format.dart';
|
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
|
||||||
import 'package:cw_core/erc20_token.dart';
|
|
||||||
import 'package:cw_core/output_info.dart';
|
|
||||||
import 'package:cw_core/transaction_info.dart';
|
|
||||||
import 'package:cw_core/transaction_priority.dart';
|
|
||||||
import 'package:cw_core/wallet_base.dart';
|
|
||||||
import 'package:cw_core/wallet_credentials.dart';
|
import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_core/transaction_history.dart';
|
||||||
import 'package:cw_core/wallet_service.dart';
|
import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:cw_ethereum/ethereum_formatter.dart';
|
|
||||||
import 'package:cw_ethereum/ethereum_mnemonics.dart';
|
|
||||||
import 'package:cw_ethereum/ethereum_transaction_credentials.dart';
|
|
||||||
import 'package:cw_ethereum/ethereum_transaction_info.dart';
|
|
||||||
import 'package:cw_ethereum/ethereum_wallet.dart';
|
|
||||||
import 'package:cw_ethereum/ethereum_wallet_creation_credentials.dart';
|
|
||||||
import 'package:cw_ethereum/ethereum_wallet_service.dart';
|
|
||||||
import 'package:cw_ethereum/ethereum_transaction_priority.dart';
|
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:cw_nano/api/wallet.dart' as nano_wallet_api;
|
||||||
|
import 'package:cw_nano/nano_balance.dart';
|
||||||
|
import 'package:cw_nano/nano_wallet_creation_credentials.dart';
|
||||||
|
|
||||||
part 'cw_nano.dart';
|
part 'cw_nano.dart';
|
||||||
|
|
||||||
Nano? nano = CWNano();
|
Nano? nano = CWNano();
|
||||||
|
|
||||||
abstract class Nano {
|
class Account {
|
||||||
List<String> getNanoWordList(String language);
|
Account({required this.id, required this.label, this.balance});
|
||||||
WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource);
|
final int id;
|
||||||
WalletCredentials createEthereumNewWalletCredentials({required String name, WalletInfo? walletInfo});
|
final String label;
|
||||||
WalletCredentials createEthereumRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password});
|
final String? balance;
|
||||||
String getAddress(WalletBase wallet);
|
|
||||||
TransactionPriority getDefaultTransactionPriority();
|
|
||||||
List<TransactionPriority> getTransactionPriorities();
|
|
||||||
TransactionPriority deserializeEthereumTransactionPriority(int raw);
|
|
||||||
int getEstimatedFee(Object wallet, TransactionPriority priority);
|
|
||||||
|
|
||||||
Object createEthereumTransactionCredentials(
|
|
||||||
List<Output> outputs, {
|
|
||||||
required TransactionPriority priority,
|
|
||||||
required CryptoCurrency currency,
|
|
||||||
int? feeRate,
|
|
||||||
});
|
|
||||||
|
|
||||||
Object createEthereumTransactionCredentialsRaw(
|
|
||||||
List<OutputInfo> outputs, {
|
|
||||||
TransactionPriority? priority,
|
|
||||||
required CryptoCurrency currency,
|
|
||||||
required int feeRate,
|
|
||||||
});
|
|
||||||
|
|
||||||
int formatterEthereumParseAmount(String amount);
|
|
||||||
double formatterEthereumAmountToDouble({required TransactionInfo transaction});
|
|
||||||
List<Erc20Token> getERC20Currencies(WalletBase wallet);
|
|
||||||
Future<void> addErc20Token(WalletBase wallet, Erc20Token token);
|
|
||||||
Future<void> deleteErc20Token(WalletBase wallet, Erc20Token token);
|
|
||||||
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress);
|
|
||||||
|
|
||||||
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class NanoWalletDetails {
|
||||||
|
@observable
|
||||||
|
late Account account;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
late NanoBalance balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Nano {
|
||||||
|
// NanoAccountList getAccountList(Object wallet);
|
||||||
|
|
||||||
|
WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource);
|
||||||
|
|
||||||
|
TransactionHistoryBase getTransactionHistory(Object wallet);
|
||||||
|
|
||||||
|
NanoWalletDetails getNanoWalletDetails(Object wallet);
|
||||||
|
|
||||||
|
WalletCredentials createNanoNewWalletCredentials({
|
||||||
|
required String name,
|
||||||
|
required String language,
|
||||||
|
String password,
|
||||||
|
});
|
||||||
|
|
||||||
|
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex);
|
||||||
|
|
||||||
|
void onStartup();
|
||||||
|
|
||||||
|
List<String> getNanoWordList(String language);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class NanoAccountList {
|
||||||
|
ObservableList<Account> get accounts;
|
||||||
|
void update(Object wallet);
|
||||||
|
void refresh(Object wallet);
|
||||||
|
List<Account> getAll(Object wallet);
|
||||||
|
Future<void> addAccount(Object wallet, {required String label});
|
||||||
|
Future<void> setLabelAccount(Object wallet, {required int accountIndex, required String label});
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cake_wallet/monero/monero.dart';
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
|
import 'package:cake_wallet/nano/nano.dart';
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
import 'package:cake_wallet/store/app_store.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||||
|
@ -45,6 +46,8 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
|
||||||
name: name, language: options as String);
|
name: name, language: options as String);
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
return ethereum!.createEthereumNewWalletCredentials(name: name);
|
return ethereum!.createEthereumNewWalletCredentials(name: name);
|
||||||
|
case WalletType.nano:
|
||||||
|
return nano!.createNanoNewWalletCredentials(name: name, language: options as String);
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected type: ${type.toString()}');;
|
throw Exception('Unexpected type: ${type.toString()}');;
|
||||||
}
|
}
|
||||||
|
|
1
model_generator.sh
Normal file → Executable file
1
model_generator.sh
Normal file → Executable file
|
@ -3,4 +3,5 @@ cd cw_monero && flutter pub get && flutter packages pub run build_runner build -
|
||||||
cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||||
cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||||
cd cw_ethereum && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_ethereum && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||||
|
cd cw_nano && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||||
flutter packages pub run build_runner build --delete-conflicting-outputs
|
flutter packages pub run build_runner build --delete-conflicting-outputs
|
|
@ -10,7 +10,7 @@ case $APP_ANDROID_TYPE in
|
||||||
CONFIG_ARGS="--monero"
|
CONFIG_ARGS="--monero"
|
||||||
;;
|
;;
|
||||||
$CAKEWALLET)
|
$CAKEWALLET)
|
||||||
CONFIG_ARGS="--monero --bitcoin --haven --ethereum"
|
CONFIG_ARGS="--monero --bitcoin --haven --ethereum --nano"
|
||||||
;;
|
;;
|
||||||
$HAVEN)
|
$HAVEN)
|
||||||
CONFIG_ARGS="--haven"
|
CONFIG_ARGS="--haven"
|
||||||
|
|
|
@ -14,12 +14,32 @@ Future<void> main(List<String> args) async {
|
||||||
final hasMonero = args.contains('${prefix}monero');
|
final hasMonero = args.contains('${prefix}monero');
|
||||||
final hasHaven = args.contains('${prefix}haven');
|
final hasHaven = args.contains('${prefix}haven');
|
||||||
final hasEthereum = args.contains('${prefix}ethereum');
|
final hasEthereum = args.contains('${prefix}ethereum');
|
||||||
|
final hasNano = args.contains('${prefix}nano');
|
||||||
|
final hasBanano = args.contains('${prefix}banano');
|
||||||
|
|
||||||
await generateBitcoin(hasBitcoin);
|
await generateBitcoin(hasBitcoin);
|
||||||
await generateMonero(hasMonero);
|
await generateMonero(hasMonero);
|
||||||
await generateHaven(hasHaven);
|
await generateHaven(hasHaven);
|
||||||
await generateEthereum(hasEthereum);
|
await generateEthereum(hasEthereum);
|
||||||
await generatePubspec(hasMonero: hasMonero, hasBitcoin: hasBitcoin, hasHaven: hasHaven, hasEthereum: hasEthereum);
|
await generateNano(hasNano);
|
||||||
await generateWalletTypes(hasMonero: hasMonero, hasBitcoin: hasBitcoin, hasHaven: hasHaven, hasEthereum: hasEthereum);
|
// await generateBanano(hasEthereum);
|
||||||
|
|
||||||
|
await generatePubspec(
|
||||||
|
hasMonero: hasMonero,
|
||||||
|
hasBitcoin: hasBitcoin,
|
||||||
|
hasHaven: hasHaven,
|
||||||
|
hasEthereum: hasEthereum,
|
||||||
|
hasNano: hasNano,
|
||||||
|
hasBanano: hasBanano,
|
||||||
|
);
|
||||||
|
await generateWalletTypes(
|
||||||
|
hasMonero: hasMonero,
|
||||||
|
hasBitcoin: hasBitcoin,
|
||||||
|
hasHaven: hasHaven,
|
||||||
|
hasEthereum: hasEthereum,
|
||||||
|
hasNano: hasNano,
|
||||||
|
hasBanano: hasBanano,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> generateBitcoin(bool hasImplementation) async {
|
Future<void> generateBitcoin(bool hasImplementation) async {
|
||||||
|
@ -105,12 +125,12 @@ abstract class Bitcoin {
|
||||||
const bitcoinEmptyDefinition = 'Bitcoin? bitcoin;\n';
|
const bitcoinEmptyDefinition = 'Bitcoin? bitcoin;\n';
|
||||||
const bitcoinCWDefinition = 'Bitcoin? bitcoin = CWBitcoin();\n';
|
const bitcoinCWDefinition = 'Bitcoin? bitcoin = CWBitcoin();\n';
|
||||||
|
|
||||||
final output = '$bitcoinCommonHeaders\n'
|
final output = '$bitcoinCommonHeaders\n' +
|
||||||
+ (hasImplementation ? '$bitcoinCWHeaders\n' : '\n')
|
(hasImplementation ? '$bitcoinCWHeaders\n' : '\n') +
|
||||||
+ (hasImplementation ? '$bitcoinCwPart\n\n' : '\n')
|
(hasImplementation ? '$bitcoinCwPart\n\n' : '\n') +
|
||||||
+ (hasImplementation ? bitcoinCWDefinition : bitcoinEmptyDefinition)
|
(hasImplementation ? bitcoinCWDefinition : bitcoinEmptyDefinition) +
|
||||||
+ '\n'
|
'\n' +
|
||||||
+ bitcoinContent;
|
bitcoinContent;
|
||||||
|
|
||||||
if (outputFile.existsSync()) {
|
if (outputFile.existsSync()) {
|
||||||
await outputFile.delete();
|
await outputFile.delete();
|
||||||
|
@ -279,12 +299,12 @@ abstract class MoneroAccountList {
|
||||||
const moneroEmptyDefinition = 'Monero? monero;\n';
|
const moneroEmptyDefinition = 'Monero? monero;\n';
|
||||||
const moneroCWDefinition = 'Monero? monero = CWMonero();\n';
|
const moneroCWDefinition = 'Monero? monero = CWMonero();\n';
|
||||||
|
|
||||||
final output = '$moneroCommonHeaders\n'
|
final output = '$moneroCommonHeaders\n' +
|
||||||
+ (hasImplementation ? '$moneroCWHeaders\n' : '\n')
|
(hasImplementation ? '$moneroCWHeaders\n' : '\n') +
|
||||||
+ (hasImplementation ? '$moneroCwPart\n\n' : '\n')
|
(hasImplementation ? '$moneroCwPart\n\n' : '\n') +
|
||||||
+ (hasImplementation ? moneroCWDefinition : moneroEmptyDefinition)
|
(hasImplementation ? moneroCWDefinition : moneroEmptyDefinition) +
|
||||||
+ '\n'
|
'\n' +
|
||||||
+ moneroContent;
|
moneroContent;
|
||||||
|
|
||||||
if (outputFile.existsSync()) {
|
if (outputFile.existsSync()) {
|
||||||
await outputFile.delete();
|
await outputFile.delete();
|
||||||
|
@ -294,7 +314,6 @@ abstract class MoneroAccountList {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> generateHaven(bool hasImplementation) async {
|
Future<void> generateHaven(bool hasImplementation) async {
|
||||||
|
|
||||||
final outputFile = File(havenOutputPath);
|
final outputFile = File(havenOutputPath);
|
||||||
const havenCommonHeaders = """
|
const havenCommonHeaders = """
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
@ -459,12 +478,12 @@ abstract class HavenAccountList {
|
||||||
const havenEmptyDefinition = 'Haven? haven;\n';
|
const havenEmptyDefinition = 'Haven? haven;\n';
|
||||||
const havenCWDefinition = 'Haven? haven = CWHaven();\n';
|
const havenCWDefinition = 'Haven? haven = CWHaven();\n';
|
||||||
|
|
||||||
final output = '$havenCommonHeaders\n'
|
final output = '$havenCommonHeaders\n' +
|
||||||
+ (hasImplementation ? '$havenCWHeaders\n' : '\n')
|
(hasImplementation ? '$havenCWHeaders\n' : '\n') +
|
||||||
+ (hasImplementation ? '$havenCwPart\n\n' : '\n')
|
(hasImplementation ? '$havenCwPart\n\n' : '\n') +
|
||||||
+ (hasImplementation ? havenCWDefinition : havenEmptyDefinition)
|
(hasImplementation ? havenCWDefinition : havenEmptyDefinition) +
|
||||||
+ '\n'
|
'\n' +
|
||||||
+ havenContent;
|
havenContent;
|
||||||
|
|
||||||
if (outputFile.existsSync()) {
|
if (outputFile.existsSync()) {
|
||||||
await outputFile.delete();
|
await outputFile.delete();
|
||||||
|
@ -474,7 +493,6 @@ abstract class HavenAccountList {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> generateEthereum(bool hasImplementation) async {
|
Future<void> generateEthereum(bool hasImplementation) async {
|
||||||
|
|
||||||
final outputFile = File(ethereumOutputPath);
|
final outputFile = File(ethereumOutputPath);
|
||||||
const ethereumCommonHeaders = """
|
const ethereumCommonHeaders = """
|
||||||
""";
|
""";
|
||||||
|
@ -541,12 +559,12 @@ abstract class Ethereum {
|
||||||
const ethereumEmptyDefinition = 'Ethereum? ethereum;\n';
|
const ethereumEmptyDefinition = 'Ethereum? ethereum;\n';
|
||||||
const ethereumCWDefinition = 'Ethereum? ethereum = CWEthereum();\n';
|
const ethereumCWDefinition = 'Ethereum? ethereum = CWEthereum();\n';
|
||||||
|
|
||||||
final output = '$ethereumCommonHeaders\n'
|
final output = '$ethereumCommonHeaders\n' +
|
||||||
+ (hasImplementation ? '$ethereumCWHeaders\n' : '\n')
|
(hasImplementation ? '$ethereumCWHeaders\n' : '\n') +
|
||||||
+ (hasImplementation ? '$ethereumCwPart\n\n' : '\n')
|
(hasImplementation ? '$ethereumCwPart\n\n' : '\n') +
|
||||||
+ (hasImplementation ? ethereumCWDefinition : ethereumEmptyDefinition)
|
(hasImplementation ? ethereumCWDefinition : ethereumEmptyDefinition) +
|
||||||
+ '\n'
|
'\n' +
|
||||||
+ ethereumContent;
|
ethereumContent;
|
||||||
|
|
||||||
if (outputFile.existsSync()) {
|
if (outputFile.existsSync()) {
|
||||||
await outputFile.delete();
|
await outputFile.delete();
|
||||||
|
@ -555,7 +573,80 @@ abstract class Ethereum {
|
||||||
await outputFile.writeAsString(output);
|
await outputFile.writeAsString(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> generatePubspec({required bool hasMonero, required bool hasBitcoin, required bool hasHaven, required bool hasEthereum}) async {
|
Future<void> generateNano(bool hasImplementation) async {
|
||||||
|
final outputFile = File(ethereumOutputPath);
|
||||||
|
const nanoCommonHeaders = """
|
||||||
|
""";
|
||||||
|
const nanoCWHeaders = """
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cw_core/wallet_credentials.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_core/transaction_history.dart';
|
||||||
|
import 'package:cw_core/wallet_service.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:cw_nano/api/wallet.dart' as nano_wallet_api;
|
||||||
|
import 'package:cw_nano/nano_balance.dart';
|
||||||
|
import 'package:cw_nano/nano_wallet_creation_credentials.dart';
|
||||||
|
""";
|
||||||
|
const nanoCwPart = "part 'cw_nano.dart';";
|
||||||
|
const nanoContent = """
|
||||||
|
abstract class Nano {
|
||||||
|
// NanoAccountList getAccountList(Object wallet);
|
||||||
|
|
||||||
|
WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource);
|
||||||
|
|
||||||
|
TransactionHistoryBase getTransactionHistory(Object wallet);
|
||||||
|
|
||||||
|
NanoWalletDetails getNanoWalletDetails(Object wallet);
|
||||||
|
|
||||||
|
WalletCredentials createNanoNewWalletCredentials({
|
||||||
|
required String name,
|
||||||
|
required String language,
|
||||||
|
String password,
|
||||||
|
});
|
||||||
|
|
||||||
|
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex);
|
||||||
|
|
||||||
|
void onStartup();
|
||||||
|
|
||||||
|
List<String> getNanoWordList(String language);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class NanoAccountList {
|
||||||
|
ObservableList<Account> get accounts;
|
||||||
|
void update(Object wallet);
|
||||||
|
void refresh(Object wallet);
|
||||||
|
List<Account> getAll(Object wallet);
|
||||||
|
Future<void> addAccount(Object wallet, {required String label});
|
||||||
|
Future<void> setLabelAccount(Object wallet, {required int accountIndex, required String label});
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
const nanoEmptyDefinition = 'Nano? nano;\n';
|
||||||
|
const nanoCWDefinition = 'Nano? nano = CWNano();\n';
|
||||||
|
|
||||||
|
final output = '$nanoCommonHeaders\n' +
|
||||||
|
(hasImplementation ? '$nanoCWHeaders\n' : '\n') +
|
||||||
|
(hasImplementation ? '$nanoCwPart\n\n' : '\n') +
|
||||||
|
(hasImplementation ? nanoCWDefinition : nanoEmptyDefinition) +
|
||||||
|
'\n' +
|
||||||
|
nanoContent;
|
||||||
|
|
||||||
|
if (outputFile.existsSync()) {
|
||||||
|
await outputFile.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
await outputFile.writeAsString(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> generatePubspec({
|
||||||
|
required bool hasMonero,
|
||||||
|
required bool hasBitcoin,
|
||||||
|
required bool hasHaven,
|
||||||
|
required bool hasEthereum,
|
||||||
|
required bool hasNano,
|
||||||
|
required bool hasBanano,
|
||||||
|
}) async {
|
||||||
const cwCore = """
|
const cwCore = """
|
||||||
cw_core:
|
cw_core:
|
||||||
path: ./cw_core
|
path: ./cw_core
|
||||||
|
@ -580,6 +671,14 @@ Future<void> generatePubspec({required bool hasMonero, required bool hasBitcoin,
|
||||||
cw_ethereum:
|
cw_ethereum:
|
||||||
path: ./cw_ethereum
|
path: ./cw_ethereum
|
||||||
""";
|
""";
|
||||||
|
const cwNano = """
|
||||||
|
cw_nano:
|
||||||
|
path: ./cw_nano
|
||||||
|
""";
|
||||||
|
const cwBanano = """
|
||||||
|
cw_nano:
|
||||||
|
path: ./cw_banano
|
||||||
|
""";
|
||||||
final inputFile = File(pubspecOutputPath);
|
final inputFile = File(pubspecOutputPath);
|
||||||
final inputText = await inputFile.readAsString();
|
final inputText = await inputFile.readAsString();
|
||||||
final inputLines = inputText.split('\n');
|
final inputLines = inputText.split('\n');
|
||||||
|
@ -604,6 +703,14 @@ Future<void> generatePubspec({required bool hasMonero, required bool hasBitcoin,
|
||||||
output += '\n$cwEthereum';
|
output += '\n$cwEthereum';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasNano) {
|
||||||
|
output += '\n$cwNano';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasBanano) {
|
||||||
|
output += '\n$cwBanano';
|
||||||
|
}
|
||||||
|
|
||||||
final outputLines = output.split('\n');
|
final outputLines = output.split('\n');
|
||||||
inputLines.insertAll(dependenciesIndex + 1, outputLines);
|
inputLines.insertAll(dependenciesIndex + 1, outputLines);
|
||||||
final outputContent = inputLines.join('\n');
|
final outputContent = inputLines.join('\n');
|
||||||
|
@ -616,7 +723,14 @@ Future<void> generatePubspec({required bool hasMonero, required bool hasBitcoin,
|
||||||
await outputFile.writeAsString(outputContent);
|
await outputFile.writeAsString(outputContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> generateWalletTypes({required bool hasMonero, required bool hasBitcoin, required bool hasHaven, required bool hasEthereum}) async {
|
Future<void> generateWalletTypes({
|
||||||
|
required bool hasMonero,
|
||||||
|
required bool hasBitcoin,
|
||||||
|
required bool hasHaven,
|
||||||
|
required bool hasEthereum,
|
||||||
|
required bool hasNano,
|
||||||
|
required bool hasBanano,
|
||||||
|
}) async {
|
||||||
final walletTypesFile = File(walletTypesPath);
|
final walletTypesFile = File(walletTypesPath);
|
||||||
|
|
||||||
if (walletTypesFile.existsSync()) {
|
if (walletTypesFile.existsSync()) {
|
||||||
|
@ -647,6 +761,14 @@ Future<void> generateWalletTypes({required bool hasMonero, required bool hasBitc
|
||||||
outputContent += '\tWalletType.haven,\n';
|
outputContent += '\tWalletType.haven,\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasNano) {
|
||||||
|
outputContent += '\tWalletType.nano,\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasBanano) {
|
||||||
|
outputContent += '\tWalletType.banano,\n';
|
||||||
|
}
|
||||||
|
|
||||||
outputContent += '];\n';
|
outputContent += '];\n';
|
||||||
await walletTypesFile.writeAsString(outputContent);
|
await walletTypesFile.writeAsString(outputContent);
|
||||||
}
|
}
|
Loading…
Reference in a new issue