mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-22 18:54:47 +00:00
remove monero stuff, work on derivation ui
This commit is contained in:
parent
c6d937ca4e
commit
2fb43e8b28
56 changed files with 368 additions and 1599 deletions
|
@ -1,83 +0,0 @@
|
|||
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();
|
||||
return [];
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
import 'dart:ffi';
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
String convertUTF8ToString({required Pointer<Utf8> pointer}) {
|
||||
final str = pointer.toDartString();
|
||||
calloc.free(pointer);
|
||||
return str;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
class ConnectionToNodeException implements Exception {
|
||||
ConnectionToNodeException({required this.message});
|
||||
|
||||
final String message;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
class CreationTransactionException implements Exception {
|
||||
CreationTransactionException({required this.message});
|
||||
|
||||
final String message;
|
||||
|
||||
@override
|
||||
String toString() => message;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
class SetupWalletException implements Exception {
|
||||
SetupWalletException({required this.message});
|
||||
|
||||
final String message;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
class WalletCreationException implements Exception {
|
||||
WalletCreationException({required this.message});
|
||||
|
||||
final String message;
|
||||
|
||||
@override
|
||||
String toString() => message;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
class WalletOpeningException implements Exception {
|
||||
WalletOpeningException({required this.message});
|
||||
|
||||
final String message;
|
||||
|
||||
@override
|
||||
String toString() => message;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
class WalletRestoreFromKeysException implements Exception {
|
||||
WalletRestoreFromKeysException({required this.message});
|
||||
|
||||
final String message;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
class WalletRestoreFromSeedException implements Exception {
|
||||
WalletRestoreFromSeedException({required this.message});
|
||||
|
||||
final String message;
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
|
||||
final DynamicLibrary moneroApi = Platform.isAndroid
|
||||
? DynamicLibrary.open("libcw_monero.so")
|
||||
: DynamicLibrary.open("cw_monero.framework/cw_monero");
|
|
@ -1,6 +0,0 @@
|
|||
class MoneroOutput {
|
||||
MoneroOutput({required this.address, required this.amount});
|
||||
|
||||
final String address;
|
||||
final String amount;
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
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();
|
|
@ -1,12 +0,0 @@
|
|||
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;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
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;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
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;
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
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();
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
import 'dart:ffi';
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
class Utf8Box extends Struct {
|
||||
external Pointer<Utf8> value;
|
||||
|
||||
String getValue() => value.toDartString();
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
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();
|
||||
}
|
|
@ -1,234 +0,0 @@
|
|||
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
|
||||
});
|
|
@ -1,130 +0,0 @@
|
|||
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();
|
|
@ -1,353 +0,0 @@
|
|||
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;
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
|
@ -1,254 +0,0 @@
|
|||
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);
|
|
@ -89,6 +89,11 @@ abstract class NanoWalletBase
|
|||
Future<void> init() async {
|
||||
final String type = (_derivationType == DerivationType.nano) ? "standard" : "hd";
|
||||
|
||||
// our "mnemonic" is actually a seedkey:
|
||||
if (!_mnemonic.contains(' ')) {
|
||||
_seedKey = _mnemonic;
|
||||
}
|
||||
|
||||
if (_seedKey == null) {
|
||||
if (_derivationType == DerivationType.nano) {
|
||||
_seedKey = bip39.mnemonicToEntropy(_mnemonic).toUpperCase();
|
||||
|
|
|
@ -255,12 +255,18 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
|||
|
||||
@override
|
||||
Future<NanoWallet> restoreFromSeed(NanoRestoreWalletFromSeedCredentials credentials) async {
|
||||
if (!bip39.validateMnemonic(credentials.mnemonic)) {
|
||||
throw nm.NanoMnemonicIsIncorrectException();
|
||||
}
|
||||
if (credentials.mnemonic.contains(' ')) {
|
||||
if (!bip39.validateMnemonic(credentials.mnemonic)) {
|
||||
throw nm.NanoMnemonicIsIncorrectException();
|
||||
}
|
||||
|
||||
if (!NanoMnemomics.validateMnemonic(credentials.mnemonic.split(' '))) {
|
||||
throw nm.NanoMnemonicIsIncorrectException();
|
||||
if (!NanoMnemomics.validateMnemonic(credentials.mnemonic.split(' '))) {
|
||||
throw nm.NanoMnemonicIsIncorrectException();
|
||||
}
|
||||
} else {
|
||||
if (credentials.mnemonic.length != 64 && credentials.mnemonic.length != 128) {
|
||||
throw Exception("Invalid seed length");
|
||||
}
|
||||
}
|
||||
|
||||
DerivationType derivationType = credentials.derivationType ?? DerivationType.nano;
|
||||
|
|
|
@ -850,11 +850,11 @@ Future setup({
|
|||
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>(
|
||||
(type, _) => WalletRestorePage(getIt.get<WalletRestoreViewModel>(param1: type)));
|
||||
|
||||
getIt.registerFactoryParam<WalletRestoreChooseDerivationViewModel, WalletType, dynamic>(
|
||||
getIt.registerFactoryParam<WalletRestoreChooseDerivationViewModel, dynamic, void>(
|
||||
(credentials, _) =>
|
||||
WalletRestoreChooseDerivationViewModel(credentials: credentials));
|
||||
|
||||
getIt.registerFactoryParam<WalletRestoreChooseDerivationPage, WalletType, dynamic>(
|
||||
getIt.registerFactoryParam<WalletRestoreChooseDerivationPage, dynamic, void>(
|
||||
(credentials, _) =>
|
||||
WalletRestoreChooseDerivationPage(getIt.get<WalletRestoreChooseDerivationViewModel>(
|
||||
param1: credentials,
|
||||
|
|
|
@ -14,7 +14,7 @@ class WalletRestoreChooseDerivationPage extends BasePage {
|
|||
@override
|
||||
Widget middle(BuildContext context) => Observer(
|
||||
builder: (_) => Text(
|
||||
"change me",
|
||||
S.current.choose_derivation,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
|
@ -32,61 +32,63 @@ class WalletRestoreChooseDerivationPage extends BasePage {
|
|||
future: walletRestoreChooseDerivationViewModel.derivations,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return CircularProgressIndicator(); // Show loading spinner while waiting
|
||||
return Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
} else if (snapshot.hasError) {
|
||||
return Text('Error: ${snapshot.error}'); // Show error if any
|
||||
return Text('Error: ${snapshot.error}');
|
||||
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
||||
return Text('No derivations available'); // Show message if no derivations are available
|
||||
return Text('No derivations available');
|
||||
} else {
|
||||
return ListView.separated(
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
separatorBuilder: (_, __) => Container(padding: EdgeInsets.only(bottom: 8)),
|
||||
separatorBuilder: (_, __) => SizedBox(),
|
||||
itemCount: snapshot.data!.length,
|
||||
itemBuilder: (__, index) {
|
||||
final derivation = snapshot.data![index];
|
||||
return InkWell(
|
||||
onTap: () async {
|
||||
Navigator.pop(context, derivation.derivationType);
|
||||
},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(left: 16, right: 16),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30.0),
|
||||
border: Border.all(
|
||||
color: getIt.get<SettingsStore>().currentTheme.type == ThemeType.bright
|
||||
? Color.fromRGBO(255, 255, 255, 0.2)
|
||||
: Colors.transparent,
|
||||
width: 1,
|
||||
return Card(
|
||||
margin: const EdgeInsets.all(8),
|
||||
elevation: 3,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
onTap: () async {
|
||||
Navigator.pop(context, derivation.derivationType);
|
||||
},
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.all(16),
|
||||
title: Center(
|
||||
child: Text(
|
||||
"${derivation.derivationType.toString().split('.').last}",
|
||||
style:
|
||||
Theme.of(context).primaryTextTheme.labelMedium!.copyWith(fontSize: 18),
|
||||
),
|
||||
),
|
||||
color: Theme.of(context).textTheme.titleLarge!.backgroundColor!,
|
||||
),
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(top: 16, left: 24, right: 24, bottom: 24),
|
||||
child: Column(
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
derivation.address,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color:
|
||||
Theme.of(context).accentTextTheme.displayMedium!.backgroundColor!,
|
||||
height: 1,
|
||||
),
|
||||
style: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.labelMedium!
|
||||
.copyWith(fontSize: 16),
|
||||
),
|
||||
Text(
|
||||
"${S.current.confirmed}: ${derivation.balance}",
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color:
|
||||
Theme.of(context).accentTextTheme.displayMedium!.backgroundColor!,
|
||||
height: 2,
|
||||
),
|
||||
style: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.labelMedium!
|
||||
.copyWith(fontSize: 16),
|
||||
),
|
||||
Text(
|
||||
"${S.current.transactions}: ${derivation.height}",
|
||||
style: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.labelMedium!
|
||||
.copyWith(fontSize: 16),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
149
lib/src/screens/restore/wallet_restore_from_seed_key_form.dart
Normal file
149
lib/src/screens/restore/wallet_restore_from_seed_key_form.dart
Normal file
|
@ -0,0 +1,149 @@
|
|||
import 'package:cake_wallet/entities/generate_name.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/seed_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/core/wallet_name_validator.dart';
|
||||
|
||||
class WalletRestoreFromSeedKeyForm extends StatefulWidget {
|
||||
WalletRestoreFromSeedKeyForm(
|
||||
{Key? key,
|
||||
required this.displayLanguageSelector,
|
||||
required this.displayBlockHeightSelector,
|
||||
required this.type,
|
||||
this.blockHeightFocusNode,
|
||||
this.onHeightOrDateEntered,
|
||||
this.onSeedChange,
|
||||
this.onLanguageChange})
|
||||
: super(key: key);
|
||||
|
||||
final WalletType type;
|
||||
final bool displayLanguageSelector;
|
||||
final bool displayBlockHeightSelector;
|
||||
final FocusNode? blockHeightFocusNode;
|
||||
final Function(bool)? onHeightOrDateEntered;
|
||||
final void Function(String)? onSeedChange;
|
||||
final void Function(String)? onLanguageChange;
|
||||
|
||||
@override
|
||||
WalletRestoreFromSeedKeyFormState createState() =>
|
||||
WalletRestoreFromSeedKeyFormState('English');
|
||||
}
|
||||
|
||||
class WalletRestoreFromSeedKeyFormState extends State<WalletRestoreFromSeedKeyForm> {
|
||||
WalletRestoreFromSeedKeyFormState(this.language)
|
||||
: seedWidgetStateKey = GlobalKey<SeedWidgetState>(),
|
||||
blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
|
||||
formKey = GlobalKey<FormState>(),
|
||||
languageController = TextEditingController(),
|
||||
nameTextEditingController = TextEditingController();
|
||||
|
||||
final GlobalKey<SeedWidgetState> seedWidgetStateKey;
|
||||
final GlobalKey<BlockchainHeightState> blockchainHeightKey;
|
||||
final TextEditingController languageController;
|
||||
final TextEditingController nameTextEditingController;
|
||||
final GlobalKey<FormState> formKey;
|
||||
String language;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_setLanguageLabel(language);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: Column(children: [
|
||||
Form(
|
||||
key: formKey,
|
||||
child: Stack(
|
||||
alignment: Alignment.centerRight,
|
||||
children: [
|
||||
BaseTextFormField(
|
||||
controller: nameTextEditingController,
|
||||
hintText: S.of(context).wallet_name,
|
||||
suffixIcon: IconButton(
|
||||
onPressed: () async {
|
||||
final rName = await generateName();
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
|
||||
setState(() {
|
||||
nameTextEditingController.text = rName;
|
||||
nameTextEditingController.selection =
|
||||
TextSelection.fromPosition(TextPosition(
|
||||
offset: nameTextEditingController.text.length));
|
||||
});
|
||||
},
|
||||
icon: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6.0),
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
width: 34,
|
||||
height: 34,
|
||||
child: Image.asset(
|
||||
'assets/images/refresh_icon.png',
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme!
|
||||
.headlineMedium!
|
||||
.decorationColor!,
|
||||
),
|
||||
),
|
||||
),
|
||||
validator: WalletNameValidator(),
|
||||
),
|
||||
],
|
||||
)),
|
||||
Container(height: 20),
|
||||
SeedWidget(
|
||||
key: seedWidgetStateKey,
|
||||
language: language,
|
||||
type: widget.type,
|
||||
onSeedChange: widget.onSeedChange),
|
||||
if (widget.displayLanguageSelector)
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => SeedLanguagePicker(
|
||||
selected: language, onItemSelected: _changeLanguage));
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: IgnorePointer(
|
||||
child: BaseTextFormField(
|
||||
controller: languageController,
|
||||
enableInteractiveSelection: false,
|
||||
readOnly: true)))),
|
||||
if (widget.displayBlockHeightSelector)
|
||||
BlockchainHeightWidget(
|
||||
focusNode: widget.blockHeightFocusNode,
|
||||
key: blockchainHeightKey,
|
||||
onHeightOrDateEntered: widget.onHeightOrDateEntered,
|
||||
hasDatePicker: widget.type == WalletType.monero)
|
||||
]));
|
||||
}
|
||||
|
||||
void _changeLanguage(String language) {
|
||||
setState(() {
|
||||
this.language = language;
|
||||
seedWidgetStateKey.currentState!.changeSeedLanguage(language);
|
||||
_setLanguageLabel(language);
|
||||
widget.onLanguageChange?.call(language);
|
||||
});
|
||||
}
|
||||
|
||||
void _setLanguageLabel(String language) =>
|
||||
languageController.text = '$language (Seed language)';
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_from_seed_key_form.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
|
@ -29,6 +30,7 @@ class WalletRestorePage extends BasePage {
|
|||
WalletRestorePage(this.walletRestoreViewModel)
|
||||
: walletRestoreFromSeedFormKey = GlobalKey<WalletRestoreFromSeedFormState>(),
|
||||
walletRestoreFromKeysFormKey = GlobalKey<WalletRestoreFromKeysFromState>(),
|
||||
walletRestoreFromSeedKeyFormKey = GlobalKey<WalletRestoreFromSeedKeyFormState>(),
|
||||
_pages = [],
|
||||
_blockHeightFocusNode = FocusNode(),
|
||||
_controller = PageController(initialPage: 0) {
|
||||
|
@ -71,6 +73,17 @@ class WalletRestorePage extends BasePage {
|
|||
}
|
||||
}));
|
||||
break;
|
||||
case WalletRestoreMode.seedKey:
|
||||
_pages.add(WalletRestoreFromSeedKeyForm(
|
||||
displayBlockHeightSelector: walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
|
||||
displayLanguageSelector: walletRestoreViewModel.hasSeedLanguageSelector,
|
||||
type: walletRestoreViewModel.type,
|
||||
key: walletRestoreFromSeedKeyFormKey,
|
||||
onSeedChange: (String seed) {
|
||||
walletRestoreViewModel.isButtonEnabled = _isValidSeedKey();
|
||||
},
|
||||
));
|
||||
break;
|
||||
case WalletRestoreMode.keys:
|
||||
_pages.add(WalletRestoreFromKeysFrom(
|
||||
key: walletRestoreFromKeysFormKey,
|
||||
|
@ -101,6 +114,7 @@ class WalletRestorePage extends BasePage {
|
|||
final List<Widget> _pages;
|
||||
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
|
||||
final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey;
|
||||
final GlobalKey<WalletRestoreFromSeedKeyFormState> walletRestoreFromSeedKeyFormKey;
|
||||
final FocusNode _blockHeightFocusNode;
|
||||
DerivationType derivationType = DerivationType.unknown;
|
||||
|
||||
|
@ -162,8 +176,14 @@ class WalletRestorePage extends BasePage {
|
|||
Expanded(
|
||||
child: PageView.builder(
|
||||
onPageChanged: (page) {
|
||||
walletRestoreViewModel.mode =
|
||||
page == 0 ? WalletRestoreMode.seed : WalletRestoreMode.keys;
|
||||
if (walletRestoreViewModel.type == WalletType.nano ||
|
||||
walletRestoreViewModel.type == WalletType.banano) {
|
||||
walletRestoreViewModel.mode =
|
||||
page == 0 ? WalletRestoreMode.seed : WalletRestoreMode.seedKey;
|
||||
} else {
|
||||
walletRestoreViewModel.mode =
|
||||
page == 0 ? WalletRestoreMode.seed : WalletRestoreMode.keys;
|
||||
}
|
||||
},
|
||||
controller: _controller,
|
||||
itemCount: _pages.length,
|
||||
|
@ -192,7 +212,7 @@ class WalletRestorePage extends BasePage {
|
|||
builder: (context) {
|
||||
return LoadingPrimaryButton(
|
||||
onPressed: () async {
|
||||
_confirmForm(context);
|
||||
await _confirmForm(context);
|
||||
},
|
||||
text: S.of(context).restore_recover,
|
||||
color: Theme.of(context).accentTextTheme!.titleSmall!.decorationColor!,
|
||||
|
@ -228,12 +248,22 @@ class WalletRestorePage extends BasePage {
|
|||
seedWords.length != WalletRestoreViewModelBase.electrumShortSeedMnemonicLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final words =
|
||||
walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.words.toSet();
|
||||
return seedWords.toSet().difference(words).toSet().isEmpty;
|
||||
}
|
||||
|
||||
bool _isValidSeedKey() {
|
||||
final seedKey =
|
||||
walletRestoreFromSeedKeyFormKey.currentState!.seedWidgetStateKey.currentState!.text;
|
||||
|
||||
if (seedKey.length != 64 && seedKey.length != 128) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Map<String, dynamic> _credentials() {
|
||||
final credentials = <String, dynamic>{};
|
||||
|
||||
|
@ -248,7 +278,7 @@ class WalletRestorePage extends BasePage {
|
|||
|
||||
credentials['name'] =
|
||||
walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.text;
|
||||
} else {
|
||||
} else if (walletRestoreViewModel.mode == WalletRestoreMode.keys) {
|
||||
credentials['address'] = walletRestoreFromKeysFormKey.currentState!.addressController.text;
|
||||
credentials['viewKey'] = walletRestoreFromKeysFormKey.currentState!.viewKeyController.text;
|
||||
credentials['spendKey'] = walletRestoreFromKeysFormKey.currentState!.spendKeyController.text;
|
||||
|
@ -256,6 +286,9 @@ class WalletRestorePage extends BasePage {
|
|||
walletRestoreFromKeysFormKey.currentState!.blockchainHeightKey.currentState!.height;
|
||||
credentials['name'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.text;
|
||||
} else if (walletRestoreViewModel.mode == WalletRestoreMode.seedKey) {
|
||||
credentials['seedKey'] =
|
||||
walletRestoreFromSeedKeyFormKey.currentState!.seedWidgetStateKey.currentState!.text;
|
||||
}
|
||||
|
||||
credentials['derivationType'] = this.derivationType;
|
||||
|
@ -263,22 +296,28 @@ class WalletRestorePage extends BasePage {
|
|||
return credentials;
|
||||
}
|
||||
|
||||
void _confirmForm(BuildContext context) async {
|
||||
Future<void> _confirmForm(BuildContext context) async {
|
||||
// Dismissing all visible keyboard to provide context for navigation
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
final formContext = walletRestoreViewModel.mode == WalletRestoreMode.seed
|
||||
? walletRestoreFromSeedFormKey.currentContext
|
||||
: walletRestoreFromKeysFormKey.currentContext;
|
||||
|
||||
late BuildContext? formContext;
|
||||
late GlobalKey<FormState>? formKey;
|
||||
late String name;
|
||||
if (walletRestoreViewModel.mode == WalletRestoreMode.seed) {
|
||||
formContext = walletRestoreFromSeedFormKey.currentContext;
|
||||
formKey = walletRestoreFromSeedFormKey.currentState!.formKey;
|
||||
name = walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.value.text;
|
||||
} else if (walletRestoreViewModel.mode == WalletRestoreMode.keys) {
|
||||
formContext = walletRestoreFromKeysFormKey.currentContext;
|
||||
formKey = walletRestoreFromKeysFormKey.currentState!.formKey;
|
||||
name = walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.value.text;
|
||||
} else if (walletRestoreViewModel.mode == WalletRestoreMode.seedKey) {
|
||||
formContext = walletRestoreFromSeedKeyFormKey.currentContext;
|
||||
formKey = walletRestoreFromSeedKeyFormKey.currentState!.formKey;
|
||||
name = walletRestoreFromSeedKeyFormKey.currentState!.nameTextEditingController.value.text;
|
||||
}
|
||||
|
||||
final formKey = walletRestoreViewModel.mode == WalletRestoreMode.seed
|
||||
? walletRestoreFromSeedFormKey.currentState!.formKey
|
||||
: walletRestoreFromKeysFormKey.currentState!.formKey;
|
||||
|
||||
final name = walletRestoreViewModel.mode == WalletRestoreMode.seed
|
||||
? walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.value.text
|
||||
: walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.value.text;
|
||||
|
||||
if (!formKey.currentState!.validate()) {
|
||||
if (!formKey!.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -287,25 +326,26 @@ class WalletRestorePage extends BasePage {
|
|||
return;
|
||||
}
|
||||
|
||||
walletRestoreViewModel.state = IsExecutingState();
|
||||
|
||||
List<DerivationType> derivationTypes =
|
||||
await walletRestoreViewModel.getDerivationType(_credentials());
|
||||
if (derivationTypes[0] == DerivationType.unknown || derivationTypes.length > 0) {
|
||||
// push screen to choose the derivation type:
|
||||
var derivationType =
|
||||
await Navigator.of(context).pushNamed(Routes.restoreWalletChooseDerivation, arguments: {
|
||||
"walletType": walletRestoreViewModel.type,
|
||||
"credentials": _credentials(),
|
||||
}) as DerivationType?;
|
||||
var derivationType = await Navigator.of(context)
|
||||
.pushNamed(Routes.restoreWalletChooseDerivation, arguments: _credentials())
|
||||
as DerivationType?;
|
||||
if (derivationType == null) {
|
||||
walletRestoreViewModel.state = InitialExecutionState();
|
||||
return;
|
||||
}
|
||||
this.derivationType = derivationType;
|
||||
}
|
||||
|
||||
print(this.derivationType);
|
||||
walletRestoreViewModel.state = InitialExecutionState();
|
||||
|
||||
// todo: re-enable
|
||||
// walletRestoreViewModel.create(options: _credentials());
|
||||
walletRestoreViewModel.create(options: _credentials());
|
||||
}
|
||||
|
||||
Future<void> showNameExistsAlert(BuildContext context) {
|
||||
|
|
|
@ -1 +1 @@
|
|||
enum WalletRestoreMode { seed, keys, txids }
|
||||
enum WalletRestoreMode { seed, keys, txids, seedKey }
|
|
@ -26,7 +26,6 @@ abstract class WalletRestoreChooseDerivationViewModelBase with Store {
|
|||
WalletRestoreChooseDerivationViewModelBase({required this.credentials})
|
||||
: mode = WalletRestoreMode.seed {}
|
||||
|
||||
|
||||
dynamic credentials;
|
||||
|
||||
@observable
|
||||
|
@ -35,7 +34,7 @@ abstract class WalletRestoreChooseDerivationViewModelBase with Store {
|
|||
Future<List<Derivation>> get derivations async {
|
||||
var list = <Derivation>[];
|
||||
|
||||
switch (getIt.get<AppStore>().wallet!.type) {
|
||||
switch ((await getIt.get<AppStore>().wallet!.type)) {
|
||||
case WalletType.nano:
|
||||
var seed = credentials['seed'] as String;
|
||||
var bip39Info =
|
||||
|
@ -43,14 +42,6 @@ abstract class WalletRestoreChooseDerivationViewModelBase with Store {
|
|||
var standardInfo =
|
||||
await NanoWalletService.getInfoFromSeedOrMnemonic(DerivationType.nano, mnemonic: seed);
|
||||
|
||||
list.add(Derivation(
|
||||
NanoUtil.getRawAsUsableString(bip39Info["balance"] as String, NanoUtil.rawPerNano),
|
||||
bip39Info["address"] as String,
|
||||
DerivationType.bip39,
|
||||
int.parse(
|
||||
bip39Info["confirmation_height"] as String,
|
||||
),
|
||||
));
|
||||
list.add(Derivation(
|
||||
NanoUtil.getRawAsUsableString(standardInfo["balance"] as String, NanoUtil.rawPerNano),
|
||||
standardInfo["address"] as String,
|
||||
|
@ -59,6 +50,16 @@ abstract class WalletRestoreChooseDerivationViewModelBase with Store {
|
|||
standardInfo["confirmation_height"] as String,
|
||||
),
|
||||
));
|
||||
|
||||
list.add(Derivation(
|
||||
NanoUtil.getRawAsUsableString(bip39Info["balance"] as String, NanoUtil.rawPerNano),
|
||||
bip39Info["address"] as String,
|
||||
DerivationType.bip39,
|
||||
int.parse(
|
||||
bip39Info["confirmation_height"] as String,
|
||||
),
|
||||
));
|
||||
|
||||
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -26,8 +26,10 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
Box<WalletInfo> walletInfoSource,
|
||||
{required WalletType type})
|
||||
: availableModes = (type == WalletType.monero || type == WalletType.haven)
|
||||
? WalletRestoreMode.values
|
||||
: [WalletRestoreMode.seed],
|
||||
? [WalletRestoreMode.seed, WalletRestoreMode.keys, WalletRestoreMode.txids]
|
||||
: (type == WalletType.nano || type == WalletType.banano)
|
||||
? [WalletRestoreMode.seed, WalletRestoreMode.seedKey]
|
||||
: [WalletRestoreMode.seed],
|
||||
hasSeedLanguageSelector = type == WalletType.monero || type == WalletType.haven,
|
||||
hasBlockchainHeightLanguageSelector = type == WalletType.monero || type == WalletType.haven,
|
||||
isButtonEnabled = false,
|
||||
|
@ -121,7 +123,8 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
|
||||
@override
|
||||
Future<List<DerivationType>> getDerivationType(dynamic options) async {
|
||||
final seed = options['seed'] as String?;
|
||||
final seedKey = options['seedKey'] as String?;
|
||||
final mnemonic = options['seed'] as String?;
|
||||
|
||||
switch (type) {
|
||||
// case WalletType.bitcoin:
|
||||
|
@ -131,7 +134,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
// return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
|
||||
// name: name, mnemonic: seed, password: password);
|
||||
case WalletType.nano:
|
||||
return await NanoWalletService.compareDerivationMethods(mnemonic: seed, seedKey: null);
|
||||
return await NanoWalletService.compareDerivationMethods(mnemonic: mnemonic, seedKey: seedKey);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -678,5 +678,6 @@
|
|||
"support_title_guides": "أدلة محفظة كعكة",
|
||||
"support_description_guides": "توثيق ودعم القضايا المشتركة",
|
||||
"support_title_other_links": "روابط دعم أخرى",
|
||||
"support_description_other_links": "انضم إلى مجتمعاتنا أو تصل إلينا شركائنا من خلال أساليب أخرى"
|
||||
}
|
||||
"support_description_other_links": "انضم إلى مجتمعاتنا أو تصل إلينا شركائنا من خلال أساليب أخرى",
|
||||
"choose_derivation": "اختر اشتقاق المحفظة"
|
||||
}
|
|
@ -674,5 +674,6 @@
|
|||
"support_title_guides": "Ръководства за портфейл за торта",
|
||||
"support_description_guides": "Документация и подкрепа за общи проблеми",
|
||||
"support_title_other_links": "Други връзки за поддръжка",
|
||||
"support_description_other_links": "Присъединете се към нашите общности или се свържете с нас нашите партньори чрез други методи"
|
||||
}
|
||||
"support_description_other_links": "Присъединете се към нашите общности или се свържете с нас нашите партньори чрез други методи",
|
||||
"choose_derivation": "Изберете производно на портфейла"
|
||||
}
|
|
@ -674,5 +674,6 @@
|
|||
"support_title_guides": "Průvodce peněženkami dortu",
|
||||
"support_description_guides": "Dokumentace a podpora běžných otázek",
|
||||
"support_title_other_links": "Další odkazy na podporu",
|
||||
"support_description_other_links": "Připojte se k našim komunitám nebo se k nám oslovte další metody"
|
||||
}
|
||||
"support_description_other_links": "Připojte se k našim komunitám nebo se k nám oslovte další metody",
|
||||
"choose_derivation": "Vyberte derivaci peněženky"
|
||||
}
|
|
@ -682,5 +682,6 @@
|
|||
"support_title_guides": "Cake Wallet Guides",
|
||||
"support_description_guides": "Dokumentation und Hilfe für bekannte Probleme",
|
||||
"support_title_other_links": "Andere Support-Links",
|
||||
"support_description_other_links": "Treten Sie unseren Communities bei oder erreichen Sie uns oder unsere Partner über andere Methoden"
|
||||
}
|
||||
"support_description_other_links": "Treten Sie unseren Communities bei oder erreichen Sie uns oder unsere Partner über andere Methoden",
|
||||
"choose_derivation": "Wählen Sie Brieftaschenableitung"
|
||||
}
|
|
@ -682,5 +682,6 @@
|
|||
"support_title_guides": "Cake Wallet guides",
|
||||
"support_description_guides": "Documentation and support for common issues",
|
||||
"support_title_other_links": "Other support links",
|
||||
"support_description_other_links": "Join our communities or reach us our our partners through other methods"
|
||||
}
|
||||
"support_description_other_links": "Join our communities or reach us our our partners through other methods",
|
||||
"choose_derivation": "Choose Wallet Derivation"
|
||||
}
|
|
@ -682,5 +682,6 @@
|
|||
"support_title_guides": "Guías de billetera para pastel",
|
||||
"support_description_guides": "Documentación y apoyo para problemas comunes",
|
||||
"support_title_other_links": "Otros enlaces de soporte",
|
||||
"support_description_other_links": "Únase a nuestras comunidades o comuníquese con nosotros nuestros socios a través de otros métodos"
|
||||
}
|
||||
"support_description_other_links": "Únase a nuestras comunidades o comuníquese con nosotros nuestros socios a través de otros métodos",
|
||||
"choose_derivation": "Elija la derivación de la billetera"
|
||||
}
|
|
@ -682,5 +682,6 @@
|
|||
"support_title_guides": "Guides de portefeuille à gâteau",
|
||||
"support_description_guides": "Documentation et soutien aux problèmes communs",
|
||||
"support_title_other_links": "Autres liens d'assistance",
|
||||
"support_description_other_links": "Rejoignez nos communautés ou contactez-nous nos partenaires à travers d'autres méthodes"
|
||||
}
|
||||
"support_description_other_links": "Rejoignez nos communautés ou contactez-nous nos partenaires à travers d'autres méthodes",
|
||||
"choose_derivation": "Choisissez la dérivation du portefeuille"
|
||||
}
|
|
@ -660,5 +660,6 @@
|
|||
"support_title_guides": "Jagorar Cake",
|
||||
"support_description_guides": "Tallafi da tallafi don batutuwa na yau da kullun",
|
||||
"support_title_other_links": "Sauran hanyoyin tallafi",
|
||||
"support_description_other_links": "Kasance tare da al'ummominmu ko kuma ka kai mu abokanmu ta hanyar wasu hanyoyi"
|
||||
}
|
||||
"support_description_other_links": "Kasance tare da al'ummominmu ko kuma ka kai mu abokanmu ta hanyar wasu hanyoyi",
|
||||
"choose_derivation": "Zaɓi walatawa"
|
||||
}
|
|
@ -682,5 +682,6 @@
|
|||
"support_title_guides": "केक वॉलेट गाइड",
|
||||
"support_description_guides": "सामान्य मुद्दों के लिए प्रलेखन और समर्थन",
|
||||
"support_title_other_links": "अन्य समर्थन लिंक",
|
||||
"support_description_other_links": "हमारे समुदायों में शामिल हों या अन्य तरीकों के माध्यम से हमारे साथी तक पहुंचें"
|
||||
}
|
||||
"support_description_other_links": "हमारे समुदायों में शामिल हों या अन्य तरीकों के माध्यम से हमारे साथी तक पहुंचें",
|
||||
"choose_derivation": "वॉलेट व्युत्पत्ति चुनें"
|
||||
}
|
|
@ -680,5 +680,6 @@
|
|||
"support_title_guides": "Vodiči za torte",
|
||||
"support_description_guides": "Dokumentacija i podrška za uobičajena pitanja",
|
||||
"support_title_other_links": "Ostale veze za podršku",
|
||||
"support_description_other_links": "Pridružite se našim zajednicama ili nam dosegnu naše partnere drugim metodama"
|
||||
}
|
||||
"support_description_other_links": "Pridružite se našim zajednicama ili nam dosegnu naše partnere drugim metodama",
|
||||
"choose_derivation": "Odaberite izvedbu novčanika"
|
||||
}
|
|
@ -670,5 +670,6 @@
|
|||
"support_title_guides": "Panduan Dompet Kue",
|
||||
"support_description_guides": "Dokumentasi dan dukungan untuk masalah umum",
|
||||
"support_title_other_links": "Tautan dukungan lainnya",
|
||||
"support_description_other_links": "Bergabunglah dengan komunitas kami atau hubungi kami mitra kami melalui metode lain"
|
||||
}
|
||||
"support_description_other_links": "Bergabunglah dengan komunitas kami atau hubungi kami mitra kami melalui metode lain",
|
||||
"choose_derivation": "Pilih dompet dompet"
|
||||
}
|
|
@ -682,5 +682,6 @@
|
|||
"support_title_guides": "Guide del portafoglio per torte",
|
||||
"support_description_guides": "Documentazione e supporto per problemi comuni",
|
||||
"support_title_other_links": "Altri collegamenti di supporto",
|
||||
"support_description_other_links": "Unisciti alle nostre comunità o raggiungici i nostri partner attraverso altri metodi"
|
||||
}
|
||||
"support_description_other_links": "Unisciti alle nostre comunità o raggiungici i nostri partner attraverso altri metodi",
|
||||
"choose_derivation": "Scegli la derivazione del portafoglio"
|
||||
}
|
|
@ -682,5 +682,6 @@
|
|||
"support_title_guides": "ケーキウォレットガイド",
|
||||
"support_description_guides": "一般的な問題のドキュメントとサポート",
|
||||
"support_title_other_links": "その他のサポートリンク",
|
||||
"support_description_other_links": "私たちのコミュニティに参加するか、他の方法を通して私たちのパートナーに連絡してください"
|
||||
}
|
||||
"support_description_other_links": "私たちのコミュニティに参加するか、他の方法を通して私たちのパートナーに連絡してください",
|
||||
"choose_derivation": "ウォレット派生を選択します"
|
||||
}
|
|
@ -680,5 +680,6 @@
|
|||
"support_title_guides": "케이크 지갑 가이드",
|
||||
"support_description_guides": "일반적인 문제에 대한 문서화 및 지원",
|
||||
"support_title_other_links": "다른 지원 링크",
|
||||
"support_description_other_links": "다른 방법을 통해 커뮤니티에 가입하거나 파트너에게 연락하십시오."
|
||||
}
|
||||
"support_description_other_links": "다른 방법을 통해 커뮤니티에 가입하거나 파트너에게 연락하십시오.",
|
||||
"choose_derivation": "지갑 파생을 선택하십시오"
|
||||
}
|
|
@ -680,5 +680,6 @@
|
|||
"support_title_guides": "ကိတ်မုန့်ပိုက်ဆံအိတ်လမ်းညွှန်များ",
|
||||
"support_description_guides": "ဘုံပြ issues နာများအတွက်စာရွက်စာတမ်းများနှင့်ထောက်ခံမှု",
|
||||
"support_title_other_links": "အခြားအထောက်အပံ့လင့်များ",
|
||||
"support_description_other_links": "ကျွန်ုပ်တို့၏လူမှုအသိုင်းအဝိုင်းများသို့ 0 င်ရောက်ပါ"
|
||||
}
|
||||
"support_description_other_links": "ကျွန်ုပ်တို့၏လူမှုအသိုင်းအဝိုင်းများသို့ 0 င်ရောက်ပါ",
|
||||
"choose_derivation": "ပိုက်ဆံအိတ်ကိုရွေးချယ်ပါ"
|
||||
}
|
|
@ -682,5 +682,6 @@
|
|||
"support_title_guides": "Cake -portemonnee gidsen",
|
||||
"support_description_guides": "Documentatie en ondersteuning voor gemeenschappelijke problemen",
|
||||
"support_title_other_links": "Andere ondersteuningslinks",
|
||||
"support_description_other_links": "Word lid van onze gemeenschappen of bereik ons onze partners via andere methoden"
|
||||
}
|
||||
"support_description_other_links": "Word lid van onze gemeenschappen of bereik ons onze partners via andere methoden",
|
||||
"choose_derivation": "Kies portemonnee -afleiding"
|
||||
}
|
|
@ -682,5 +682,6 @@
|
|||
"support_title_guides": "Przewodniki portfela ciasta",
|
||||
"support_description_guides": "Dokumentacja i wsparcie dla typowych problemów",
|
||||
"support_title_other_links": "Inne linki wsparcia",
|
||||
"support_description_other_links": "Dołącz do naszych społeczności lub skontaktuj się z nami naszymi partnerami za pomocą innych metod"
|
||||
}
|
||||
"support_description_other_links": "Dołącz do naszych społeczności lub skontaktuj się z nami naszymi partnerami za pomocą innych metod",
|
||||
"choose_derivation": "Wybierz wyprowadzenie portfela"
|
||||
}
|
|
@ -681,5 +681,6 @@
|
|||
"support_title_guides": "Guias da carteira de bolo",
|
||||
"support_description_guides": "Documentação e suporte para problemas comuns",
|
||||
"support_title_other_links": "Outros links de suporte",
|
||||
"support_description_other_links": "Junte -se às nossas comunidades ou chegue a nós nossos parceiros por meio de outros métodos"
|
||||
}
|
||||
"support_description_other_links": "Junte -se às nossas comunidades ou chegue a nós nossos parceiros por meio de outros métodos",
|
||||
"choose_derivation": "Escolha a derivação da carteira"
|
||||
}
|
|
@ -682,5 +682,6 @@
|
|||
"support_title_guides": "Корт -гиды",
|
||||
"support_description_guides": "Документация и поддержка общих вопросов",
|
||||
"support_title_other_links": "Другие ссылки на поддержку",
|
||||
"support_description_other_links": "Присоединяйтесь к нашим сообществам или охватите нас наших партнеров с помощью других методов"
|
||||
}
|
||||
"support_description_other_links": "Присоединяйтесь к нашим сообществам или охватите нас наших партнеров с помощью других методов",
|
||||
"choose_derivation": "Выберите вывод кошелька"
|
||||
}
|
|
@ -680,5 +680,6 @@
|
|||
"support_title_guides": "คู่มือกระเป๋าเงินเค้ก",
|
||||
"support_description_guides": "เอกสารและการสนับสนุนสำหรับปัญหาทั่วไป",
|
||||
"support_title_other_links": "ลิงค์สนับสนุนอื่น ๆ",
|
||||
"support_description_other_links": "เข้าร่วมชุมชนของเราหรือเข้าถึงเราพันธมิตรของเราผ่านวิธีการอื่น ๆ"
|
||||
}
|
||||
"support_description_other_links": "เข้าร่วมชุมชนของเราหรือเข้าถึงเราพันธมิตรของเราผ่านวิธีการอื่น ๆ",
|
||||
"choose_derivation": "เลือก Wallet Derivation"
|
||||
}
|
|
@ -680,5 +680,6 @@
|
|||
"support_title_guides": "Kek Cüzdan Kılavuzları",
|
||||
"support_description_guides": "Ortak sorunlara belge ve destek",
|
||||
"support_title_other_links": "Diğer destek bağlantıları",
|
||||
"support_description_other_links": "Topluluklarımıza katılın veya ortaklarımıza diğer yöntemlerle bize ulaşın"
|
||||
}
|
||||
"support_description_other_links": "Topluluklarımıza katılın veya ortaklarımıza diğer yöntemlerle bize ulaşın",
|
||||
"choose_derivation": "Cüzdan türevini seçin"
|
||||
}
|
|
@ -682,5 +682,6 @@
|
|||
"support_title_guides": "Поклики для гаманців тортів",
|
||||
"support_description_guides": "Документація та підтримка загальних питань",
|
||||
"support_title_other_links": "Інші посилання на підтримку",
|
||||
"support_description_other_links": "Приєднуйтесь до наших спільнот або досягайте нас нашими партнерами іншими методами"
|
||||
}
|
||||
"support_description_other_links": "Приєднуйтесь до наших спільнот або досягайте нас нашими партнерами іншими методами",
|
||||
"choose_derivation": "Виберіть деривацію гаманця"
|
||||
}
|
|
@ -674,5 +674,6 @@
|
|||
"support_title_guides": "کیک پرس گائڈز",
|
||||
"support_description_guides": "عام مسائل کے لئے دستاویزات اور مدد",
|
||||
"support_title_other_links": "دوسرے سپورٹ لنکس",
|
||||
"support_description_other_links": "ہماری برادریوں میں شامل ہوں یا دوسرے طریقوں سے ہمارے شراکت داروں تک پہنچیں"
|
||||
}
|
||||
"support_description_other_links": "ہماری برادریوں میں شامل ہوں یا دوسرے طریقوں سے ہمارے شراکت داروں تک پہنچیں",
|
||||
"choose_derivation": "پرس سے ماخوذ منتخب کریں"
|
||||
}
|
|
@ -676,5 +676,6 @@
|
|||
"support_title_guides": "Akara oyinbo Awọn Itọsọna Awọki oyinbo",
|
||||
"support_description_guides": "Iwe ati atilẹyin fun awọn ọran ti o wọpọ",
|
||||
"support_title_other_links": "Awọn ọna asopọ atilẹyin miiran",
|
||||
"support_description_other_links": "Darapọ mọ awọn agbegbe wa tabi de wa awọn alabaṣepọ wa nipasẹ awọn ọna miiran"
|
||||
}
|
||||
"support_description_other_links": "Darapọ mọ awọn agbegbe wa tabi de wa awọn alabaṣepọ wa nipasẹ awọn ọna miiran",
|
||||
"choose_derivation": "Yan awọn apamọwọ apamọwọ"
|
||||
}
|
|
@ -681,5 +681,6 @@
|
|||
"support_title_guides": "蛋糕钱包指南",
|
||||
"support_description_guides": "对常见问题的文档和支持",
|
||||
"support_title_other_links": "其他支持链接",
|
||||
"support_description_other_links": "加入我们的社区或通过其他方法与我们联系我们的合作伙伴"
|
||||
}
|
||||
"support_description_other_links": "加入我们的社区或通过其他方法与我们联系我们的合作伙伴",
|
||||
"choose_derivation": "选择钱包推导"
|
||||
}
|
Loading…
Reference in a new issue