import 'dart:ffi'; import 'package:cw_haven/api/convert_utf8_to_string.dart'; import 'package:cw_haven/api/monero_output.dart'; import 'package:cw_haven/api/structs/ut8_box.dart'; import 'package:ffi/ffi.dart'; import 'package:flutter/foundation.dart'; import 'package:cw_haven/api/signatures.dart'; import 'package:cw_haven/api/types.dart'; import 'package:cw_haven/api/haven_api.dart'; import 'package:cw_haven/api/structs/transaction_info_row.dart'; import 'package:cw_haven/api/structs/pending_transaction.dart'; import 'package:cw_haven/api/exceptions/creation_transaction_exception.dart'; final transactionsRefreshNative = havenApi .lookup>('transactions_refresh') .asFunction(); final transactionsCountNative = havenApi .lookup>('transactions_count') .asFunction(); final transactionsGetAllNative = havenApi .lookup>('transactions_get_all') .asFunction(); final transactionCreateNative = havenApi .lookup>('transaction_create') .asFunction(); final transactionCreateMultDestNative = havenApi .lookup>('transaction_create_mult_dest') .asFunction(); final transactionCommitNative = havenApi .lookup>('transaction_commit') .asFunction(); final getTxKeyNative = havenApi .lookup>('get_tx_key') .asFunction(); String getTxKey(String txId) { final txIdPointer = Utf8.toUtf8(txId); final keyPointer = getTxKeyNative(txIdPointer); free(txIdPointer); if (keyPointer != null) { return convertUTF8ToString(pointer: keyPointer); } return null; } void refreshTransactions() => transactionsRefreshNative(); int countOfTransactions() => transactionsCountNative(); List getAllTransations() { final size = transactionsCountNative(); final transactionsPointer = transactionsGetAllNative(); final transactionsAddresses = transactionsPointer.asTypedList(size); return transactionsAddresses .map((addr) => Pointer.fromAddress(addr).ref) .toList(); } PendingTransactionDescription createTransactionSync( {String address, String assetType, String paymentId, String amount, int priorityRaw, int accountIndex = 0}) { final addressPointer = Utf8.toUtf8(address); final assetTypePointer = Utf8.toUtf8(assetType); final paymentIdPointer = Utf8.toUtf8(paymentId); final amountPointer = amount != null ? Utf8.toUtf8(amount) : nullptr; final errorMessagePointer = allocate(); final pendingTransactionRawPointer = allocate(); final created = transactionCreateNative( addressPointer, assetTypePointer, paymentIdPointer, amountPointer, priorityRaw, accountIndex, errorMessagePointer, pendingTransactionRawPointer) != 0; free(addressPointer); free(assetTypePointer); free(paymentIdPointer); if (amountPointer != nullptr) { free(amountPointer); } if (!created) { final message = errorMessagePointer.ref.getValue(); free(errorMessagePointer); throw CreationTransactionException(message: message); } return PendingTransactionDescription( amount: pendingTransactionRawPointer.ref.amount, fee: pendingTransactionRawPointer.ref.fee, hash: pendingTransactionRawPointer.ref.getHash(), pointerAddress: pendingTransactionRawPointer.address); } PendingTransactionDescription createTransactionMultDestSync( {List outputs, String assetType, String paymentId, int priorityRaw, int accountIndex = 0}) { final int size = outputs.length; final List> addressesPointers = outputs.map((output) => Utf8.toUtf8(output.address)).toList(); final Pointer> addressesPointerPointer = allocate(count: size); final List> amountsPointers = outputs.map((output) => Utf8.toUtf8(output.amount)).toList(); final Pointer> amountsPointerPointer = allocate(count: size); for (int i = 0; i < size; i++) { addressesPointerPointer[i] = addressesPointers[i]; amountsPointerPointer[i] = amountsPointers[i]; } final assetTypePointer = Utf8.toUtf8(assetType); final paymentIdPointer = Utf8.toUtf8(paymentId); final errorMessagePointer = allocate(); final pendingTransactionRawPointer = allocate(); final created = transactionCreateMultDestNative( addressesPointerPointer, assetTypePointer, paymentIdPointer, amountsPointerPointer, size, priorityRaw, accountIndex, errorMessagePointer, pendingTransactionRawPointer) != 0; free(addressesPointerPointer); free(assetTypePointer); free(amountsPointerPointer); addressesPointers.forEach((element) => free(element)); amountsPointers.forEach((element) => free(element)); free(paymentIdPointer); if (!created) { final message = errorMessagePointer.ref.getValue(); free(errorMessagePointer); throw CreationTransactionException(message: message); } return PendingTransactionDescription( amount: pendingTransactionRawPointer.ref.amount, fee: pendingTransactionRawPointer.ref.fee, hash: pendingTransactionRawPointer.ref.getHash(), pointerAddress: pendingTransactionRawPointer.address); } void commitTransactionFromPointerAddress({int address}) => commitTransaction( transactionPointer: Pointer.fromAddress(address)); void commitTransaction({Pointer transactionPointer}) { final errorMessagePointer = allocate(); final isCommited = transactionCommitNative(transactionPointer, errorMessagePointer) != 0; if (!isCommited) { final message = errorMessagePointer.ref.getValue(); free(errorMessagePointer); throw CreationTransactionException(message: message); } } PendingTransactionDescription _createTransactionSync(Map args) { final address = args['address'] as String; final assetType = args['assetType'] 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, assetType: assetType, paymentId: paymentId, amount: amount, priorityRaw: priorityRaw, accountIndex: accountIndex); } PendingTransactionDescription _createTransactionMultDestSync(Map args) { final outputs = args['outputs'] as List; final assetType = args['assetType'] as String; final paymentId = args['paymentId'] as String; final priorityRaw = args['priorityRaw'] as int; final accountIndex = args['accountIndex'] as int; return createTransactionMultDestSync( outputs: outputs, assetType: assetType, paymentId: paymentId, priorityRaw: priorityRaw, accountIndex: accountIndex); } Future createTransaction( {String address, String assetType, String paymentId = '', String amount, int priorityRaw, int accountIndex = 0}) => compute(_createTransactionSync, { 'address': address, 'assetType': assetType, 'paymentId': paymentId, 'amount': amount, 'priorityRaw': priorityRaw, 'accountIndex': accountIndex }); Future createTransactionMultDest( {List outputs, String assetType, String paymentId = '', int priorityRaw, int accountIndex = 0}) => compute(_createTransactionMultDestSync, { 'outputs': outputs, 'assetType': assetType, 'paymentId': paymentId, 'priorityRaw': priorityRaw, 'accountIndex': accountIndex });