refactor interface changes back into the interface

This commit is contained in:
sneurlax 2023-09-19 22:14:34 -05:00
parent ef38e58b57
commit 4180cf6c44
3 changed files with 131 additions and 125 deletions

View file

@ -11,18 +11,11 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:math'; import 'dart:math';
import 'package:decimal/decimal.dart';
import 'package:fusiondart/src/models/address.dart' as fusion_address;
import 'package:fusiondart/src/models/input.dart' as fusion_input;
import 'package:fusiondart/src/models/output.dart' as fusion_output;
import 'package:fusiondart/src/models/transaction.dart' as fusion_tx;
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/input.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/input.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/output.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/output.dart';
import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
part 'transaction.g.dart'; part 'transaction.g.dart';
@ -238,108 +231,6 @@ class Transaction {
return Tuple2(transaction, address); return Tuple2(transaction, address);
} }
} }
// Convert to fusiondart's Transaction type.
//
// This is bad because in the FusionWalletInterface in getTransactionsByAddress
// we already getAllTransactions, then for each transaction here we also getTransaction
// for each transaction again. But the data we need--the input's value--isn't
// here anyways.
Future<fusion_tx.Transaction> toFusionTransaction(
CachedElectrumX cachedElectrumX) async {
// Initialize Fusion Dart's Transaction object.
fusion_tx.Transaction fusionTransaction = fusion_tx.Transaction();
// Map the Inputs and Outputs to Fusion Dart's format.
//
// This takes an exqcessive amount of time because we have to get the
// transaction for each input. We already have the transaction for each
// input in getTransactionsByAddress, but we don't have the input's value.
// So we have to get the transaction again here.
fusionTransaction.Inputs = await Future.wait(inputs.map((e) async {
// Find input amount.
print("2 getting tx ${e.txid}");
Map<String, dynamic> _tx = await cachedElectrumX.getTransaction(
coin: Coin.bitcoincash,
txHash: e.txid,
verbose: true); // TODO is verbose needed?
// Check if output amount is available.
if (_tx == null) {
throw Exception("Transaction not found for input: ${e.txid}");
}
if (_tx["vout"] == null) {
throw Exception("Vout in transaction ${e.txid} is null");
}
if (_tx["vout"][e.vout] == null) {
throw Exception("Vout index ${e.vout} in transaction is null");
}
if (_tx["vout"][e.vout]["value"] == null) {
throw Exception("Value of vout index ${e.vout} in transaction is null");
}
// Assign vout value to amount.
final value = Amount.fromDecimal(
Decimal.parse(_tx["vout"][e.vout]["value"].toString()),
fractionDigits: Coin.bitcoincash.decimals,
);
return fusion_input.Input(
prevTxid: utf8.encode(e.txid), // TODO verify this is what we want.
prevIndex: e.vout, // TODO verify this is what we want.
pubKey: utf8.encode(address.value.toString()), // TODO fix public key.
amount: value.raw.toInt(),
);
}).toList());
fusionTransaction.Outputs = outputs.map((e) {
/*
if (e.scriptPubKey == null) {
// TODO calculate scriptPubKey if it is null.
}
*/
fusion_address.DerivationPath? derivationPath;
List<int>? pubKey;
// Validate that we have all the required data.
if (address.value == null) {
// TODO calculate address if it is null.
throw Exception(
"address value is null for input: ${e.scriptPubKeyAddress}");
} else {
if (address.value!.publicKey.isEmpty || e.scriptPubKey != null) {
pubKey = utf8.encode(e.scriptPubKey!);
// TODO is this valid?
} else {
pubKey = address.value!.publicKey;
}
if (address.value!.derivationPath != null) {
derivationPath = fusion_address.DerivationPath(
address.value!.derivationPath!.toString());
} else {
// TODO calculate derivation path if it is null.
/*
throw Exception(
"derivationPath is null for input: ${e.scriptPubKeyAddress}");
*/
}
}
// TODO handle case where address.value.publicKey is empty and e.scriptPubKey is null
return fusion_output.Output(
addr: fusion_address.Address(
addr: e.scriptPubKeyAddress,
publicKey: pubKey,
derivationPath: derivationPath,
),
value: e.value,
);
}).toList();
return fusionTransaction;
}
} }
// Used in Isar db and stored there as int indexes so adding/removing values // Used in Isar db and stored there as int indexes so adding/removing values

View file

@ -8,10 +8,8 @@
* *
*/ */
import 'dart:convert';
import 'dart:math'; import 'dart:math';
import 'package:fusiondart/src/models/input.dart' as FusionInput;
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
part 'utxo.g.dart'; part 'utxo.g.dart';
@ -147,14 +145,3 @@ class UTXO {
@ignore @ignore
int get hashCode => Object.hashAll([walletId, txid, vout]); int get hashCode => Object.hashAll([walletId, txid, vout]);
} }
extension ToFusionInput on UTXO {
FusionInput.Input toFusionInput({required List<int> pubKey}) {
return FusionInput.Input(
prevTxid: utf8.encode(txid),
prevIndex: vout,
pubKey: pubKey,
amount: value,
);
}
}

View file

@ -2,16 +2,18 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:decimal/decimal.dart';
import 'package:fusiondart/fusiondart.dart'; import 'package:fusiondart/fusiondart.dart';
import 'package:fusiondart/src/models/address.dart' as fusion_address; import 'package:fusiondart/src/models/address.dart' as fusion_address;
import 'package:fusiondart/src/models/input.dart' as fusion_input; import 'package:fusiondart/src/models/input.dart' as fusion_input;
import 'package:fusiondart/src/models/output.dart' as fusion_output;
import 'package:fusiondart/src/models/transaction.dart' as fusion_tx; import 'package:fusiondart/src/models/transaction.dart' as fusion_tx;
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/db/isar/main_db.dart';
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/services/tor_service.dart';
import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
import 'package:stackwallet/utilities/stack_file_system.dart'; import 'package:stackwallet/utilities/stack_file_system.dart';
@ -243,8 +245,10 @@ mixin FusionWalletInterface {
// Find public key. // Find public key.
print("1 getting tx ${e.txid}"); print("1 getting tx ${e.txid}");
Map<String, dynamic> tx = await _cachedElectrumX.getTransaction(coin: _coin, Map<String, dynamic> tx = await _cachedElectrumX.getTransaction(
txHash: e.txid, verbose: true); // TODO is verbose needed? coin: _coin,
txHash: e.txid,
verbose: true); // TODO is verbose needed?
// Check if scriptPubKey is available. // Check if scriptPubKey is available.
if (tx["vout"] == null) { if (tx["vout"] == null) {
@ -380,3 +384,127 @@ mixin FusionWalletInterface {
"TODO refreshFusion eg look up number of fusion participants connected/coordinating"); "TODO refreshFusion eg look up number of fusion participants connected/coordinating");
} }
} }
/// An extension of Stack Wallet's Transaction class that adds CashFusion functionality.
extension FusionTransaction on Transaction {
// WIP.
Future<fusion_tx.Transaction> toFusionTransaction(
CachedElectrumX cachedElectrumX) async {
// Initialize Fusion Dart's Transaction object.
fusion_tx.Transaction fusionTransaction = fusion_tx.Transaction();
// WIP.
fusionTransaction.Inputs = await Future.wait(inputs.map((e) async {
// Find input amount.
Map<String, dynamic> _tx = await cachedElectrumX.getTransaction(
coin: Coin.bitcoincash,
txHash: e.txid,
verbose: true); // TODO is verbose needed?
// Check if output amount is available.
if (_tx.isEmpty) {
throw Exception("Transaction not found for input: ${e.txid}");
}
if (_tx["vout"] == null) {
throw Exception("Vout in transaction ${e.txid} is null");
}
if (_tx["vout"][e.vout] == null) {
throw Exception("Vout index ${e.vout} in transaction is null");
}
if (_tx["vout"][e.vout]["value"] == null) {
throw Exception("Value of vout index ${e.vout} in transaction is null");
}
// TODO replace with conditional chaining?
// Assign vout value to amount.
final value = Amount.fromDecimal(
Decimal.parse(_tx["vout"][e.vout]["value"].toString()),
fractionDigits: Coin.bitcoincash.decimals,
);
return fusion_input.Input(
prevTxid: utf8.encode(e.txid), // TODO verify this is what we want.
prevIndex: e.vout, // TODO verify this is what we want.
pubKey: utf8.encode(address.value.toString()), // TODO fix public key.
amount: value.raw.toInt(),
);
}).toList());
fusionTransaction.Outputs = outputs.map((e) {
/*
if (e.scriptPubKey == null) {
// TODO calculate scriptPubKey if it is null.
}
*/
fusion_address.DerivationPath? derivationPath;
List<int>? pubKey;
// Validate that we have all the required data.
if (address.value == null) {
// TODO calculate address if it is null.
throw Exception(
"address value is null for input: ${e.scriptPubKeyAddress}");
} else {
if (address.value!.publicKey.isEmpty || e.scriptPubKey != null) {
pubKey = utf8.encode(e.scriptPubKey!);
// TODO is this valid?
} else {
pubKey = address.value!
.publicKey; // TODO IMPORTANT: this address may not be *the* address in question :)
}
if (address.value!.derivationPath != null) {
derivationPath = fusion_address.DerivationPath(
address.value!.derivationPath!.toString());
} else {
// TODO calculate derivation path if it is null.
/*
throw Exception(
"derivationPath is null for input: ${e.scriptPubKeyAddress}");
*/
}
}
// TODO handle case where address.value.publicKey is empty and e.scriptPubKey is null
return fusion_output.Output(
addr: fusion_address.Address(
addr: e.scriptPubKeyAddress,
publicKey: pubKey,
derivationPath: derivationPath,
),
value: e.value,
);
}).toList();
return fusionTransaction;
}
}
/// An extension of Stack Wallet's UTXO class that adds CashFusion functionality.
///
/// This class is used to convert Stack Wallet's UTXO class to FusionDart's
/// Input and Output classes.
extension FusionUTXO on UTXO {
/// Converts a Stack Wallet UTXO to a FusionDart Input.
fusion_input.Input toFusionInput({required List<int> pubKey}) {
return fusion_input.Input(
prevTxid: utf8.encode(txid), // TODO verify this is what we want.
prevIndex: vout, // TODO verify this is what we want.
pubKey: pubKey, // TODO fix public key.
amount: value,
);
}
/// Converts a Stack Wallet UTXO to a FusionDart Output.
fusion_output.Output toFusionOutput({required String address}) {
return fusion_output.Output(
addr: fusion_address.Address(
addr: address,
publicKey: utf8.encode(address.toString()), // TODO fix public key.
derivationPath: null, // TODO fix derivation path.
),
value: value,
);
}
}