2020-05-12 12:04:54 +00:00
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
|
|
|
import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
|
2020-09-21 11:50:26 +00:00
|
|
|
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
|
2020-08-25 16:32:40 +00:00
|
|
|
import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart';
|
2020-09-21 11:50:26 +00:00
|
|
|
import 'package:cake_wallet/entities/transaction_direction.dart';
|
|
|
|
import 'package:cake_wallet/entities/transaction_info.dart';
|
|
|
|
import 'package:cake_wallet/entities/format_amount.dart';
|
2020-05-12 12:04:54 +00:00
|
|
|
|
|
|
|
class BitcoinTransactionInfo extends TransactionInfo {
|
|
|
|
BitcoinTransactionInfo(
|
2020-09-21 11:50:26 +00:00
|
|
|
{@required String id,
|
2020-05-12 12:04:54 +00:00
|
|
|
@required int height,
|
|
|
|
@required int amount,
|
|
|
|
@required TransactionDirection direction,
|
|
|
|
@required bool isPending,
|
2020-08-25 16:32:40 +00:00
|
|
|
@required DateTime date,
|
2020-08-29 10:19:27 +00:00
|
|
|
@required int confirmations}) {
|
2020-09-21 11:50:26 +00:00
|
|
|
this.id = id;
|
2020-05-12 12:04:54 +00:00
|
|
|
this.height = height;
|
|
|
|
this.amount = amount;
|
|
|
|
this.direction = direction;
|
|
|
|
this.date = date;
|
|
|
|
this.isPending = isPending;
|
2020-08-29 10:19:27 +00:00
|
|
|
this.confirmations = confirmations;
|
2020-05-12 12:04:54 +00:00
|
|
|
}
|
|
|
|
|
2020-08-25 16:32:40 +00:00
|
|
|
factory BitcoinTransactionInfo.fromElectrumVerbose(Map<String, Object> obj,
|
|
|
|
{@required List<BitcoinAddressRecord> addresses, @required int height}) {
|
|
|
|
final addressesSet = addresses.map((addr) => addr.address).toSet();
|
|
|
|
final id = obj['txid'] as String;
|
|
|
|
final vins = obj['vin'] as List<Object> ?? [];
|
|
|
|
final vout = (obj['vout'] as List<Object> ?? []);
|
|
|
|
final date = obj['time'] is int
|
|
|
|
? DateTime.fromMillisecondsSinceEpoch((obj['time'] as int) * 1000)
|
|
|
|
: DateTime.now();
|
|
|
|
final confirmations = obj['confirmations'] as int ?? 0;
|
|
|
|
var direction = TransactionDirection.incoming;
|
|
|
|
|
|
|
|
for (dynamic vin in vins) {
|
|
|
|
final vout = vin['vout'] as int;
|
|
|
|
final out = vin['tx']['vout'][vout] as Map;
|
|
|
|
final outAddresses =
|
|
|
|
(out['scriptPubKey']['addresses'] as List<Object>)?.toSet();
|
|
|
|
|
|
|
|
if (outAddresses?.intersection(addressesSet)?.isNotEmpty ?? false) {
|
|
|
|
direction = TransactionDirection.outgoing;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
final amount = vout.fold(0, (int acc, dynamic out) {
|
|
|
|
final outAddresses =
|
|
|
|
out['scriptPubKey']['addresses'] as List<Object> ?? [];
|
|
|
|
final ntrs = outAddresses.toSet().intersection(addressesSet);
|
|
|
|
var amount = acc;
|
|
|
|
|
|
|
|
if ((direction == TransactionDirection.incoming && ntrs.isNotEmpty) ||
|
|
|
|
(direction == TransactionDirection.outgoing && ntrs.isEmpty)) {
|
|
|
|
amount += doubleToBitcoinAmount(out['value'] as double ?? 0.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return amount;
|
|
|
|
});
|
|
|
|
|
|
|
|
return BitcoinTransactionInfo(
|
|
|
|
id: id,
|
|
|
|
height: height,
|
|
|
|
isPending: false,
|
|
|
|
direction: direction,
|
|
|
|
amount: amount,
|
|
|
|
date: date,
|
|
|
|
confirmations: confirmations);
|
|
|
|
}
|
|
|
|
|
|
|
|
factory BitcoinTransactionInfo.fromHexAndHeader(String hex,
|
|
|
|
{List<String> addresses, int height, int timestamp, int confirmations}) {
|
2020-05-12 12:04:54 +00:00
|
|
|
final tx = bitcoin.Transaction.fromHex(hex);
|
|
|
|
var exist = false;
|
|
|
|
var amount = 0;
|
|
|
|
|
2020-08-25 16:32:40 +00:00
|
|
|
if (addresses != null) {
|
|
|
|
tx.outs.forEach((out) {
|
|
|
|
try {
|
|
|
|
final p2pkh = bitcoin.P2PKH(
|
|
|
|
data: PaymentData(output: out.script), network: bitcoin.bitcoin);
|
|
|
|
exist = addresses.contains(p2pkh.data.address);
|
2020-05-12 12:04:54 +00:00
|
|
|
|
2020-08-25 16:32:40 +00:00
|
|
|
if (exist) {
|
|
|
|
amount += out.value;
|
|
|
|
}
|
|
|
|
} catch (_) {}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
final date = timestamp != null
|
|
|
|
? DateTime.fromMillisecondsSinceEpoch(timestamp * 1000)
|
|
|
|
: DateTime.now();
|
2020-05-12 12:04:54 +00:00
|
|
|
|
|
|
|
return BitcoinTransactionInfo(
|
|
|
|
id: tx.getId(),
|
2020-08-25 16:32:40 +00:00
|
|
|
height: height,
|
2020-05-12 12:04:54 +00:00
|
|
|
isPending: false,
|
|
|
|
direction: TransactionDirection.incoming,
|
|
|
|
amount: amount,
|
2020-08-25 16:32:40 +00:00
|
|
|
date: date,
|
|
|
|
confirmations: confirmations);
|
2020-05-12 12:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
factory BitcoinTransactionInfo.fromJson(Map<String, dynamic> data) {
|
|
|
|
return BitcoinTransactionInfo(
|
|
|
|
id: data['id'] as String,
|
|
|
|
height: data['height'] as int,
|
|
|
|
amount: data['amount'] as int,
|
|
|
|
direction: parseTransactionDirectionFromInt(data['direction'] as int),
|
|
|
|
date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int),
|
2020-08-25 16:32:40 +00:00
|
|
|
isPending: data['isPending'] as bool,
|
|
|
|
confirmations: data['confirmations'] as int);
|
2020-05-12 12:04:54 +00:00
|
|
|
}
|
|
|
|
|
2020-07-23 12:20:52 +00:00
|
|
|
String _fiatAmount;
|
|
|
|
|
|
|
|
@override
|
2020-08-25 16:32:40 +00:00
|
|
|
String amountFormatted() =>
|
|
|
|
'${formatAmount(bitcoinAmountToString(amount: amount))} BTC';
|
2020-07-23 12:20:52 +00:00
|
|
|
|
2020-05-12 12:04:54 +00:00
|
|
|
@override
|
2020-07-23 12:20:52 +00:00
|
|
|
String fiatAmount() => _fiatAmount ?? '';
|
2020-05-12 12:04:54 +00:00
|
|
|
|
|
|
|
@override
|
2020-07-23 12:20:52 +00:00
|
|
|
void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount);
|
2020-05-12 12:04:54 +00:00
|
|
|
|
|
|
|
Map<String, dynamic> toJson() {
|
2020-08-25 16:32:40 +00:00
|
|
|
final m = <String, dynamic>{};
|
2020-05-12 12:04:54 +00:00
|
|
|
m['id'] = id;
|
|
|
|
m['height'] = height;
|
|
|
|
m['amount'] = amount;
|
|
|
|
m['direction'] = direction.index;
|
|
|
|
m['date'] = date.millisecondsSinceEpoch;
|
|
|
|
m['isPending'] = isPending;
|
2020-08-25 16:32:40 +00:00
|
|
|
m['confirmations'] = confirmations;
|
2020-05-12 12:04:54 +00:00
|
|
|
return m;
|
|
|
|
}
|
|
|
|
}
|