multiple wallets

new lib
minor fixes
This commit is contained in:
Czarek Nakamoto 2024-04-16 17:15:20 +02:00 committed by cyan
parent 176150cc55
commit dcf6140444
12 changed files with 97 additions and 231 deletions

View file

@ -1,6 +1,6 @@
# TODO(mrcyjanek): Cleanup, this is borrowed from unnamed_monero_wallet repo. # TODO(mrcyjanek): Cleanup, this is borrowed from unnamed_monero_wallet repo.
MONERO_C_TAG=v0.18.3.3-RC21 MONERO_C_TAG=v0.18.3.3-RC27
LIBCPP_SHARED_SO_TAG=latest-RC1 LIBCPP_SHARED_SO_TAG=latest-RC1
LIBCPP_SHARED_SO_NDKVERSION=r17c LIBCPP_SHARED_SO_NDKVERSION=r17c

View file

@ -245,8 +245,8 @@ packages:
dependency: transitive dependency: transitive
description: description:
path: "." path: "."
ref: master ref: ada81417cb53d8b0e34022df1dd3d9dc1fe62ab5
resolved-ref: "08c5a32cbcf1f04dbae5826c83abda8fb0dbdcce" resolved-ref: ada81417cb53d8b0e34022df1dd3d9dc1fe62ab5
url: "https://git.mrcyjanek.net/mrcyjanek/monero.dart" url: "https://git.mrcyjanek.net/mrcyjanek/monero.dart"
source: git source: git
version: "0.0.0" version: "0.0.0"

View file

@ -2,6 +2,18 @@ import 'package:cw_monero/api/wallet.dart';
import 'package:monero/monero.dart' as monero; import 'package:monero/monero.dart' as monero;
monero.wallet? wptr = null; monero.wallet? wptr = null;
int _wlptrForW = 0;
monero.WalletListener? _wlptr = null;
monero.WalletListener getWlptr() {
if (wptr!.address == _wlptrForW) return _wlptr!;
_wlptrForW = wptr!.address;
_wlptr = monero.MONERO_cw_getWalletListener(wptr!);
return _wlptr!;
}
monero.SubaddressAccount? subaddressAccount; monero.SubaddressAccount? subaddressAccount;
bool isUpdating = false; bool isUpdating = false;

View file

@ -1,25 +1,3 @@
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 { class PendingTransactionDescription {
PendingTransactionDescription({ PendingTransactionDescription({

View file

@ -1,14 +1,23 @@
import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/account_list.dart';
import 'package:cw_monero/api/wallet.dart'; import 'package:cw_monero/api/wallet.dart';
import 'package:monero/monero.dart' as monero; import 'package:monero/monero.dart' as monero;
bool isUpdating = false; bool isUpdating = false;
monero.Subaddress? subaddressPtr = null;
class SubaddressInfoMetadata {
SubaddressInfoMetadata({
required this.accountIndex,
});
int accountIndex;
}
SubaddressInfoMetadata? subaddress = null;
void refreshSubaddresses({required int accountIndex}) { void refreshSubaddresses({required int accountIndex}) {
try { try {
isUpdating = true; isUpdating = true;
subaddressPtr = monero.Wallet_subaddress(wptr!); subaddress = SubaddressInfoMetadata(accountIndex: accountIndex);
monero.Subaddress_refresh(subaddressPtr!,accountIndex: accountIndex, label: '');
isUpdating = false; isUpdating = false;
} catch (e) { } catch (e) {
isUpdating = false; isUpdating = false;
@ -16,17 +25,29 @@ void refreshSubaddresses({required int accountIndex}) {
} }
} }
List<monero.SubaddressRow> getAllSubaddresses() { class Subaddress {
monero.Subaddress_refresh(subaddressPtr!, Subaddress({
accountIndex: 0, required this.addressIndex,
label: '' // BUG: by me (mrcyjanek), it isn't used, will remove. required this.accountIndex,
);
final size = monero.Subaddress_getAll_size(subaddressPtr!);
return List.generate(size, (index) {
return monero.Subaddress_getAll_byIndex(subaddressAccount!, index: index);
}); });
String get address => monero.Wallet_address(
wptr!,
accountIndex: accountIndex,
addressIndex: addressIndex,
);
final int addressIndex;
final int accountIndex;
String get label => monero.Wallet_getSubaddressLabel(wptr!, accountIndex: accountIndex, addressIndex: addressIndex);
}
List<Subaddress> getAllSubaddresses() {
final size = monero.Wallet_numSubaddresses(wptr!, accountIndex: subaddress!.accountIndex);
return List.generate(size, (index) {
return Subaddress(
accountIndex: subaddress!.accountIndex,
addressIndex: index,
);
}).reversed.toList();
} }
void addSubaddressSync({required int accountIndex, required String label}) { void addSubaddressSync({required int accountIndex, required String label}) {

View file

@ -1,10 +1,8 @@
import 'dart:ffi';
import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/account_list.dart';
import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart'; import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart';
import 'package:cw_monero/api/monero_output.dart'; import 'package:cw_monero/api/monero_output.dart';
import 'package:cw_monero/api/structs/pending_transaction.dart'; import 'package:cw_monero/api/structs/pending_transaction.dart';
import 'package:ffi/ffi.dart';
import 'package:monero/monero.dart' as monero; import 'package:monero/monero.dart' as monero;
@ -39,16 +37,6 @@ PendingTransactionDescription createTransactionSync(
String? amount, String? amount,
int accountIndex = 0, int accountIndex = 0,
List<String> preferredInputs = const []}) { List<String> preferredInputs = const []}) {
final amountPointer = amount != null ? amount.toNativeUtf8() : nullptr;
final int preferredInputsSize = preferredInputs.length;
final List<Pointer<Utf8>> preferredInputsPointers =
preferredInputs.map((output) => output.toNativeUtf8()).toList();
final Pointer<Pointer<Utf8>> preferredInputsPointerPointer = calloc(preferredInputsSize);
for (int i = 0; i < preferredInputsSize; i++) {
preferredInputsPointerPointer[i] = preferredInputsPointers[i];
}
final amt = amount == null ? 0 : monero.Wallet_amountFromString(amount); final amt = amount == null ? 0 : monero.Wallet_amountFromString(amount);
final pendingTx = monero.Wallet_createTransaction( final pendingTx = monero.Wallet_createTransaction(
@ -74,12 +62,17 @@ PendingTransactionDescription createTransactionSync(
throw CreationTransactionException(message: message); throw CreationTransactionException(message: message);
} }
final rAmt = monero.PendingTransaction_amount(pendingTx);
final rFee = monero.PendingTransaction_fee(pendingTx);
final rHash = monero.PendingTransaction_txid(pendingTx, '');
final rTxKey = rHash;
return PendingTransactionDescription( return PendingTransactionDescription(
amount: monero.PendingTransaction_amount(wptr!), amount: rAmt,
fee: monero.PendingTransaction_fee(wptr!), fee: rFee,
hash: monero.PendingTransaction_txid(wptr!, ''), hash: rHash,
hex: '', hex: '',
txKey: monero.PendingTransaction_txid(wptr!, ''), txKey: rTxKey,
pointerAddress: pendingTx.address, pointerAddress: pendingTx.address,
); );
} }

View file

@ -1,153 +0,0 @@
import 'dart:ffi';
import 'package:cw_monero/api/structs/coins_info_row.dart';
import 'package:cw_monero/api/structs/pending_transaction.dart';
import 'package:cw_monero/api/structs/transaction_info_row.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 RestoreWalletFromSpendKey = int Function(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>?, 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 GetTransaction = Pointer<TransactionInfoRow> Function(Pointer<Utf8> txId);
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<Pointer<Utf8>> preferredInputs,
int preferredInputsSize,
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<Pointer<Utf8>> preferredInputs,
int preferredInputsSize,
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();
typedef RefreshCoins = void Function(int);
typedef CoinsCount = int Function();
typedef GetCoin = Pointer<CoinsInfoRow> Function(int);
typedef FreezeCoin = void Function(int);
typedef ThawCoin = void Function(int);
typedef SignMessage = Pointer<Utf8> Function(Pointer<Utf8>, Pointer<Utf8>);

View file

@ -6,12 +6,19 @@ import 'package:monero/monero.dart' as monero;
int _boolToInt(bool value) => value ? 1 : 0; int _boolToInt(bool value) => value ? 1 : 0;
int getSyncingHeight() => monero.Wallet_blockChainHeight(wptr!); int getSyncingHeight() => monero.MONERO_cw_WalletListener_height(getWlptr());
bool isNeededToRefresh() => false; // TODO(mrcyjanek): ? bool isNeededToRefresh() {
final ret = monero.MONERO_cw_WalletListener_isNeedToRefresh(getWlptr());
bool isNewTransactionExist() => false; monero.MONERO_cw_WalletListener_resetNeedToRefresh(getWlptr());
return ret;
}
bool isNewTransactionExist() {
final ret = monero.MONERO_cw_WalletListener_isNewTransactionExist(getWlptr());
monero.MONERO_cw_WalletListener_resetIsNewTransactionExist(getWlptr());
return ret;
}
String getFilename() => monero.Wallet_filename(wptr!); String getFilename() => monero.Wallet_filename(wptr!);
// TODO(mrcyjanek): Cake polyseed support // TODO(mrcyjanek): Cake polyseed support

View file

@ -1,4 +1,6 @@
import 'dart:ffi';
import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/account_list.dart';
import 'package:cw_monero/api/exceptions/wallet_creation_exception.dart'; import 'package:cw_monero/api/exceptions/wallet_creation_exception.dart';
import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart'; import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
@ -7,7 +9,6 @@ import 'package:cw_monero/api/exceptions/wallet_restore_from_seed_exception.dart
import 'package:cw_monero/api/wallet.dart'; import 'package:cw_monero/api/wallet.dart';
import 'package:ffi/ffi.dart'; import 'package:ffi/ffi.dart';
import 'package:monero/monero.dart' as monero; import 'package:monero/monero.dart' as monero;
import 'dart:ffi';
monero.WalletManager? _wmPtr; monero.WalletManager? _wmPtr;
final monero.WalletManager wmPtr = Pointer.fromAddress((() { final monero.WalletManager wmPtr = Pointer.fromAddress((() {
@ -135,12 +136,20 @@ void restoreWalletFromSpendKeySync(
storeSync(); storeSync();
} }
String _lastOpenedWallet = "";
void loadWallet({ void loadWallet({
required String path, required String path,
required String password, required String password,
int nettype = 0}) { int nettype = 0}) {
try { try {
wptr ??= monero.WalletManager_openWallet(wmPtr, path: path, password: password); if (wptr == null || path != _lastOpenedWallet) {
if (wptr != null) {
monero.Wallet_store(wptr!);
}
wptr = monero.WalletManager_openWallet(wmPtr, path: path, password: password);
_lastOpenedWallet = path;
}
} catch (e) { } catch (e) {
print(e); print(e);
} }

View file

@ -1,9 +1,8 @@
import 'package:flutter/services.dart'; import 'package:cw_core/subaddress.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_monero/api/coins_info.dart'; import 'package:cw_monero/api/coins_info.dart';
import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list; import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list;
import 'package:cw_core/subaddress.dart'; import 'package:flutter/services.dart';
import 'package:monero/monero.dart' as monero; import 'package:mobx/mobx.dart';
part 'monero_subaddress_list.g.dart'; part 'monero_subaddress_list.g.dart';
@ -51,10 +50,10 @@ abstract class MoneroSubaddressListBase with Store {
subaddresses = [primary] + rest.toList(); subaddresses = [primary] + rest.toList();
} }
return subaddresses.map((subaddressRow) { return subaddresses.map((s) {
final label = monero.SubaddressRow_getLabel(subaddressRow); final address = s.address;
final id = monero.SubaddressRow_getRowId(subaddressRow); final label = s.label;
final address = monero.SubaddressRow_getAddress(subaddressRow); final id = s.addressIndex;
final hasDefaultAddressName = final hasDefaultAddressName =
label.toLowerCase() == 'Primary account'.toLowerCase() || label.toLowerCase() == 'Primary account'.toLowerCase() ||
label.toLowerCase() == 'Untitled account'.toLowerCase(); label.toLowerCase() == 'Untitled account'.toLowerCase();
@ -125,7 +124,7 @@ abstract class MoneroSubaddressListBase with Store {
Future<List<Subaddress>> _getAllUnusedAddresses( Future<List<Subaddress>> _getAllUnusedAddresses(
{required int accountIndex, required String label}) async { {required int accountIndex, required String label}) async {
final allAddresses = subaddress_list.getAllSubaddresses(); final allAddresses = subaddress_list.getAllSubaddresses();
final lastAddress = monero.SubaddressRow_getAddress(allAddresses.last); final lastAddress = allAddresses.last.address;
if (allAddresses.isEmpty || _usedAddresses.contains(lastAddress)) { if (allAddresses.isEmpty || _usedAddresses.contains(lastAddress)) {
final isAddressUnused = await _newSubaddress(accountIndex: accountIndex, label: label); final isAddressUnused = await _newSubaddress(accountIndex: accountIndex, label: label);
if (!isAddressUnused) { if (!isAddressUnused) {
@ -134,10 +133,10 @@ abstract class MoneroSubaddressListBase with Store {
} }
return allAddresses return allAddresses
.map((subaddressRow) { .map((s) {
final id = monero.SubaddressRow_getRowId(subaddressRow); final id = s.addressIndex;
final address = monero.SubaddressRow_getAddress(subaddressRow); final address = s.address;
final label = monero.SubaddressRow_getLabel(subaddressRow); final label = s.label;
return Subaddress( return Subaddress(
id: id, id: id,
address: address, address: address,
@ -154,8 +153,8 @@ abstract class MoneroSubaddressListBase with Store {
return subaddress_list return subaddress_list
.getAllSubaddresses() .getAllSubaddresses()
.where((subaddressRow) { .where((s) {
final address = monero.SubaddressRow_getAddress(subaddressRow); final address = s.address;
return !_usedAddresses.contains(address); return !_usedAddresses.contains(address);
}) })
.isNotEmpty; .isNotEmpty;

View file

@ -414,8 +414,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: master ref: ada81417cb53d8b0e34022df1dd3d9dc1fe62ab5
resolved-ref: "08c5a32cbcf1f04dbae5826c83abda8fb0dbdcce" resolved-ref: ada81417cb53d8b0e34022df1dd3d9dc1fe62ab5
url: "https://git.mrcyjanek.net/mrcyjanek/monero.dart" url: "https://git.mrcyjanek.net/mrcyjanek/monero.dart"
source: git source: git
version: "0.0.0" version: "0.0.0"

View file

@ -25,7 +25,7 @@ dependencies:
monero: monero:
git: git:
url: https://git.mrcyjanek.net/mrcyjanek/monero.dart url: https://git.mrcyjanek.net/mrcyjanek/monero.dart
ref: master ref: ada81417cb53d8b0e34022df1dd3d9dc1fe62ab5
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: