mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
Rbf fixes issues op return data plus ThorChain (#1648)
* total out amount issue * fix empty inputs and outputs addresses for new tx * fix sum value of utxo not spending * Update configure.dart * Update electrum_wallet.dart * receiving address * review fixes * add op_return data * fix rbf transaction with a memo * add memo check for ThorChain trade * code enhancement [skip ci] * code enhancement [skip ci] * directly use fromElectrumBundle function to update transaction info --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
parent
8524e238b0
commit
40f85d215b
4 changed files with 65 additions and 24 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:cw_bitcoin/address_from_output.dart';
|
import 'package:cw_bitcoin/address_from_output.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
|
@ -7,10 +9,12 @@ import 'package:cw_core/transaction_direction.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
import 'package:cw_core/format_amount.dart';
|
import 'package:cw_core/format_amount.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:hex/hex.dart';
|
||||||
|
|
||||||
class ElectrumTransactionBundle {
|
class ElectrumTransactionBundle {
|
||||||
ElectrumTransactionBundle(this.originalTransaction,
|
ElectrumTransactionBundle(this.originalTransaction,
|
||||||
{required this.ins, required this.confirmations, this.time});
|
{required this.ins, required this.confirmations, this.time});
|
||||||
|
|
||||||
final BtcTransaction originalTransaction;
|
final BtcTransaction originalTransaction;
|
||||||
final List<BtcTransaction> ins;
|
final List<BtcTransaction> ins;
|
||||||
final int? time;
|
final int? time;
|
||||||
|
@ -125,7 +129,24 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
||||||
for (final out in bundle.originalTransaction.outputs) {
|
for (final out in bundle.originalTransaction.outputs) {
|
||||||
totalOutAmount += out.amount.toInt();
|
totalOutAmount += out.amount.toInt();
|
||||||
final addressExists = addresses.contains(addressFromOutputScript(out.scriptPubKey, network));
|
final addressExists = addresses.contains(addressFromOutputScript(out.scriptPubKey, network));
|
||||||
outputAddresses.add(addressFromOutputScript(out.scriptPubKey, network));
|
final address = addressFromOutputScript(out.scriptPubKey, network);
|
||||||
|
|
||||||
|
if (address.isNotEmpty) outputAddresses.add(address);
|
||||||
|
|
||||||
|
// Check if the script contains OP_RETURN
|
||||||
|
final script = out.scriptPubKey.script;
|
||||||
|
if (script.contains('OP_RETURN')) {
|
||||||
|
final index = script.indexOf('OP_RETURN');
|
||||||
|
if (index + 1 <= script.length) {
|
||||||
|
try {
|
||||||
|
final opReturnData = script[index + 1].toString();
|
||||||
|
final decodedString = utf8.decode(HEX.decode(opReturnData));
|
||||||
|
outputAddresses.add('OP_RETURN:$decodedString');
|
||||||
|
} catch (_) {
|
||||||
|
outputAddresses.add('OP_RETURN:');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (addressExists) {
|
if (addressExists) {
|
||||||
receivedAmounts.add(out.amount.toInt());
|
receivedAmounts.add(out.amount.toInt());
|
||||||
|
|
|
@ -43,6 +43,7 @@ import 'package:hive/hive.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:rxdart/subjects.dart';
|
import 'package:rxdart/subjects.dart';
|
||||||
import 'package:sp_scanner/sp_scanner.dart';
|
import 'package:sp_scanner/sp_scanner.dart';
|
||||||
|
import 'package:hex/hex.dart';
|
||||||
|
|
||||||
part 'electrum_wallet.g.dart';
|
part 'electrum_wallet.g.dart';
|
||||||
|
|
||||||
|
@ -1413,6 +1414,7 @@ abstract class ElectrumWalletBase
|
||||||
List<ECPrivate> privateKeys = [];
|
List<ECPrivate> privateKeys = [];
|
||||||
|
|
||||||
var allInputsAmount = 0;
|
var allInputsAmount = 0;
|
||||||
|
String? memo;
|
||||||
|
|
||||||
// Add inputs
|
// Add inputs
|
||||||
for (var i = 0; i < bundle.originalTransaction.inputs.length; i++) {
|
for (var i = 0; i < bundle.originalTransaction.inputs.length; i++) {
|
||||||
|
@ -1451,6 +1453,22 @@ abstract class ElectrumWalletBase
|
||||||
// Create a list of available outputs
|
// Create a list of available outputs
|
||||||
final outputs = <BitcoinOutput>[];
|
final outputs = <BitcoinOutput>[];
|
||||||
for (final out in bundle.originalTransaction.outputs) {
|
for (final out in bundle.originalTransaction.outputs) {
|
||||||
|
|
||||||
|
// Check if the script contains OP_RETURN
|
||||||
|
final script = out.scriptPubKey.script;
|
||||||
|
if (script.contains('OP_RETURN') && memo == null) {
|
||||||
|
final index = script.indexOf('OP_RETURN');
|
||||||
|
if (index + 1 <= script.length) {
|
||||||
|
try {
|
||||||
|
final opReturnData = script[index + 1].toString();
|
||||||
|
memo = utf8.decode(HEX.decode(opReturnData));
|
||||||
|
continue;
|
||||||
|
} catch (_) {
|
||||||
|
throw Exception('Cannot decode OP_RETURN data');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final address = addressFromOutputScript(out.scriptPubKey, network);
|
final address = addressFromOutputScript(out.scriptPubKey, network);
|
||||||
final btcAddress = addressTypeFromStr(address, network);
|
final btcAddress = addressTypeFromStr(address, network);
|
||||||
outputs.add(BitcoinOutput(address: btcAddress, value: BigInt.from(out.amount.toInt())));
|
outputs.add(BitcoinOutput(address: btcAddress, value: BigInt.from(out.amount.toInt())));
|
||||||
|
@ -1507,6 +1525,8 @@ abstract class ElectrumWalletBase
|
||||||
outputs: outputs,
|
outputs: outputs,
|
||||||
fee: BigInt.from(newFee),
|
fee: BigInt.from(newFee),
|
||||||
network: network,
|
network: network,
|
||||||
|
memo: memo,
|
||||||
|
outputOrdering: BitcoinOrdering.none,
|
||||||
enableRBF: true,
|
enableRBF: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2036,27 +2056,13 @@ abstract class ElectrumWalletBase
|
||||||
tx.inputAddresses!.isEmpty ||
|
tx.inputAddresses!.isEmpty ||
|
||||||
tx.outputAddresses == null ||
|
tx.outputAddresses == null ||
|
||||||
tx.outputAddresses!.isEmpty) {
|
tx.outputAddresses!.isEmpty) {
|
||||||
List<String> inputAddresses = [];
|
tx = ElectrumTransactionInfo.fromElectrumBundle(
|
||||||
List<String> outputAddresses = [];
|
bundle,
|
||||||
|
walletInfo.type,
|
||||||
for (int i = 0; i < bundle.originalTransaction.inputs.length; i++) {
|
network,
|
||||||
final input = bundle.originalTransaction.inputs[i];
|
addresses: addressesSet,
|
||||||
final inputTransaction = bundle.ins[i];
|
height: tx.height,
|
||||||
final vout = input.txIndex;
|
);
|
||||||
final outTransaction = inputTransaction.outputs[vout];
|
|
||||||
final address = addressFromOutputScript(outTransaction.scriptPubKey, network);
|
|
||||||
|
|
||||||
if (address.isNotEmpty) inputAddresses.add(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < bundle.originalTransaction.outputs.length; i++) {
|
|
||||||
final out = bundle.originalTransaction.outputs[i];
|
|
||||||
final address = addressFromOutputScript(out.scriptPubKey, network);
|
|
||||||
|
|
||||||
if (address.isNotEmpty) outputAddresses.add(address);
|
|
||||||
}
|
|
||||||
tx.inputAddresses = inputAddresses;
|
|
||||||
tx.outputAddresses = outputAddresses;
|
|
||||||
|
|
||||||
transactionHistory.addOne(tx);
|
transactionHistory.addOne(tx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -845,6 +845,13 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((trade.memo == null || trade.memo!.isEmpty)) {
|
||||||
|
return CreateTradeResult(
|
||||||
|
result: false,
|
||||||
|
errorMessage: 'Memo is required for Thorchain trade',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final currenciesToCheckPattern = RegExp('0x[0-9a-zA-Z]');
|
final currenciesToCheckPattern = RegExp('0x[0-9a-zA-Z]');
|
||||||
|
|
||||||
// Perform checks for payOutAddress
|
// Perform checks for payOutAddress
|
||||||
|
|
|
@ -392,8 +392,15 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transactionInfo.outputAddresses != null && transactionInfo.outputAddresses!.isNotEmpty) {
|
if (transactionInfo.outputAddresses != null && transactionInfo.outputAddresses!.isNotEmpty) {
|
||||||
RBFListItems.add(StandardExpandableListItem(
|
final outputAddresses = transactionInfo.outputAddresses!.map((element) {
|
||||||
title: S.current.outputs, expandableItems: transactionInfo.outputAddresses!));
|
if (element.contains('OP_RETURN:') && element.length > 40) {
|
||||||
|
return element.substring(0, 40) + '...';
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
RBFListItems.add(
|
||||||
|
StandardExpandableListItem(title: S.current.outputs, expandableItems: outputAddresses));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue