add tezos transaction

This commit is contained in:
detherminal 2023-08-24 11:51:48 -06:00 committed by julian
parent c10763b4c7
commit d755fb4182
4 changed files with 136 additions and 117 deletions

View file

@ -0,0 +1,54 @@
import 'dart:convert';
import 'dart:math';
import 'package:http/http.dart';
import 'package:stackwallet/services/coins/tezos/api/tezos_transaction.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
class TezosAPI {
static const String _baseURL = 'https://api.tzstats.com';
Future<List<TezosTransaction>?> getTransactions(String address) async {
try {
String transactionsCall = "$_baseURL/explorer/account/$address/operations";
var response = jsonDecode(
await get(Uri.parse(transactionsCall)).then((value) => value.body));
List<TezosTransaction> txs = [];
for (var tx in response as List) {
if (tx["type"] == "transaction") {
final theTx = TezosTransaction(
hash: tx["hash"] as String,
height: tx["height"] as int,
timestamp: DateTime.parse(tx["time"].toString()).toUtc().millisecondsSinceEpoch ~/ 1000,
amountInMicroTez: double.parse((tx["volume"] * pow(10, Coin.tezos.decimals)).toString()).toInt(),
feeInMicroTez: double.parse((tx["fee"] * pow(10, Coin.tezos.decimals)).toString()).toInt(),
senderAddress: tx["sender"] as String,
receiverAddress: tx["receiver"] as String
);
txs.add(theTx);
}
}
return txs;
} catch (e) {
Logging.instance.log(
"Error occured while getting transactions for $address: $e",
level: LogLevel.Error);
}
return null;
}
Future<int?> getFeeEstimationFromLastDays(int days) async {
try {
var api = "$_baseURL/series/op?start_date=today&collapse=$days";
var response = jsonDecode((await get(Uri.parse(api))).body);
double totalFees = response[0][4] as double;
int totalTxs = response[0][8] as int;
return ((totalFees / totalTxs * Coin.tezos.decimals).floor());
} catch (e) {
Logging.instance.log("Error occured while getting fee estimation: $e",
level: LogLevel.Error);
}
return null;
}
}

View file

@ -0,0 +1,19 @@
class TezosTransaction {
final String hash;
final int height;
final int timestamp;
final int amountInMicroTez;
final int feeInMicroTez;
final String senderAddress;
final String receiverAddress;
TezosTransaction({
required this.hash,
required this.height,
required this.timestamp,
required this.amountInMicroTez,
required this.feeInMicroTez,
required this.senderAddress,
required this.receiverAddress,
});
}

View file

@ -1,111 +0,0 @@
import 'dart:convert';
import 'dart:math';
import 'package:http/http.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:tuple/tuple.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart';
import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
class TezosAPI {
static const String _baseURL = 'https://api.tzstats.com';
Future<List<Tuple2<Transaction, Address>>?> getTransactions(
String walletId, String address) async {
try {
String transactionsCall = "$_baseURL/explorer/account/$address/operations";
var response = jsonDecode(
await get(Uri.parse(transactionsCall)).then((value) => value.body));
List<Tuple2<Transaction, Address>> txs = [];
for (var tx in response as List) {
if (tx["type"] == "transaction") {
TransactionType txType;
final String myAddress = address;
final String senderAddress = tx["sender"] as String;
final String targetAddress = tx["receiver"] as String;
if (senderAddress == myAddress && targetAddress == myAddress) {
txType = TransactionType.sentToSelf;
} else if (senderAddress == myAddress) {
txType = TransactionType.outgoing;
} else if (targetAddress == myAddress) {
txType = TransactionType.incoming;
} else {
txType = TransactionType.unknown;
}
var amount = double.parse((tx["volume"] * pow(10, Coin.tezos.decimals)).toString()).toInt();
var fee = double.parse((tx["fee"] * pow(10, Coin.tezos.decimals)).toString()).toInt();
var theTx = Transaction(
walletId: walletId,
txid: tx["hash"].toString(),
timestamp: DateTime.parse(tx["time"].toString())
.toUtc()
.millisecondsSinceEpoch ~/
1000,
type: txType,
subType: TransactionSubType.none,
amount: amount,
amountString: Amount(
rawValue:
BigInt.parse((amount).toInt().toString()),
fractionDigits: Coin.tezos.decimals)
.toJsonString(),
fee: fee,
height: int.parse(tx["height"].toString()),
isCancelled: false,
isLelantus: false,
slateId: "",
otherData: "",
inputs: [],
outputs: [],
nonce: 0,
numberOfMessages: null,
);
final AddressSubType subType;
switch (txType) {
case TransactionType.incoming:
case TransactionType.sentToSelf:
subType = AddressSubType.receiving;
break;
case TransactionType.outgoing:
case TransactionType.unknown:
subType = AddressSubType.unknown;
break;
}
final theAddress = Address(
walletId: walletId,
value: targetAddress,
publicKey: [],
derivationIndex: 0,
derivationPath: null,
type: AddressType.unknown,
subType: subType,
);
txs.add(Tuple2(theTx, theAddress));
}
}
return txs;
} catch (e) {
Logging.instance.log(
"Error occured while getting transactions for $address: $e",
level: LogLevel.Error);
}
return null;
}
Future<int?> getFeeEstimation() async {
try {
var api = "$_baseURL/series/op?start_date=today&collapse=1d";
var response = jsonDecode((await get(Uri.parse(api))).body);
double totalFees = response[0][4] as double;
int totalTxs = response[0][8] as int;
return ((totalFees / totalTxs * Coin.tezos.decimals).floor());
} catch (e) {
Logging.instance.log("Error occured while getting fee estimation: $e",
level: LogLevel.Error);
}
return null;
}
}

View file

@ -12,7 +12,8 @@ import 'package:stackwallet/models/node_model.dart';
import 'package:stackwallet/models/paymint/fee_object_model.dart';
import 'package:stackwallet/networking/http.dart';
import 'package:stackwallet/services/coins/coin_service.dart';
import 'package:stackwallet/services/coins/tezos/tezos_api.dart';
import 'package:stackwallet/services/coins/tezos/api/tezos_api.dart';
import 'package:stackwallet/services/coins/tezos/api/tezos_transaction.dart';
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart';
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
@ -244,7 +245,7 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
int? feePerTx = await tezosAPI.getFeeEstimation();
int? feePerTx = await tezosAPI.getFeeEstimationFromLastDays(1);
feePerTx ??= 0;
return Amount(
rawValue: BigInt.from(feePerTx),
@ -260,7 +261,7 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override
Future<FeeObject> get fees async {
int? feePerTx = await tezosAPI.getFeeEstimation();
int? feePerTx = await tezosAPI.getFeeEstimationFromLastDays(1);
feePerTx ??= 0;
Logging.instance.log("feePerTx:$feePerTx", level: LogLevel.Info);
return FeeObject(
@ -516,15 +517,71 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
}
Future<void> updateTransactions() async {
var txs =
await tezosAPI.getTransactions(walletId, await currentReceivingAddress);
List<TezosTransaction>? txs =
await tezosAPI.getTransactions(await currentReceivingAddress);
Logging.instance.log("Transactions: $txs", level: LogLevel.Info);
if (txs == null) {
return;
} else if (txs.isEmpty) {
return;
}
await db.addNewTransactionData(txs, walletId);
List<Tuple2<Transaction, Address>> transactions = [];
for (var theTx in txs) {
var txType = TransactionType.unknown;
var selfAddress = await currentReceivingAddress;
if (selfAddress == theTx.senderAddress) {
txType = TransactionType.outgoing;
} else if (selfAddress == theTx.receiverAddress) {
txType = TransactionType.incoming;
} else if (selfAddress == theTx.receiverAddress &&
selfAddress == theTx.senderAddress) {
txType = TransactionType.sentToSelf;
}
var transaction = Transaction(
walletId: walletId,
txid: theTx.hash,
timestamp: theTx.timestamp,
type: txType,
subType: TransactionSubType.none,
amount: theTx.amountInMicroTez,
amountString: Amount(
rawValue: BigInt.parse(theTx.amountInMicroTez.toString()),
fractionDigits: coin.decimals,
).toJsonString(),
fee: theTx.feeInMicroTez,
height: theTx.height,
isCancelled: false,
isLelantus: false,
slateId: "",
otherData: "",
inputs: [],
outputs: [],
nonce: 0,
numberOfMessages: null,
);
final AddressSubType subType;
switch (txType) {
case TransactionType.incoming:
case TransactionType.sentToSelf:
subType = AddressSubType.receiving;
break;
case TransactionType.outgoing:
case TransactionType.unknown:
subType = AddressSubType.unknown;
break;
}
final theAddress = Address(
walletId: walletId,
value: theTx.receiverAddress,
publicKey: [],
derivationIndex: 0,
derivationPath: null,
type: AddressType.unknown,
subType: subType,
);
transactions.add(Tuple2(transaction, theAddress));
}
await db.addNewTransactionData(transactions, walletId);
}
Future<void> updateChainHeight() async {