From d755fb4182e4ccd46fa792a892978430306990de Mon Sep 17 00:00:00 2001 From: detherminal <76167420+detherminal@users.noreply.github.com> Date: Thu, 24 Aug 2023 11:51:48 -0600 Subject: [PATCH] add tezos transaction --- lib/services/coins/tezos/api/tezos_api.dart | 54 +++++++++ .../coins/tezos/api/tezos_transaction.dart | 19 +++ lib/services/coins/tezos/tezos_api.dart | 111 ------------------ lib/services/coins/tezos/tezos_wallet.dart | 69 ++++++++++- 4 files changed, 136 insertions(+), 117 deletions(-) create mode 100644 lib/services/coins/tezos/api/tezos_api.dart create mode 100644 lib/services/coins/tezos/api/tezos_transaction.dart delete mode 100644 lib/services/coins/tezos/tezos_api.dart diff --git a/lib/services/coins/tezos/api/tezos_api.dart b/lib/services/coins/tezos/api/tezos_api.dart new file mode 100644 index 000000000..fdbd97581 --- /dev/null +++ b/lib/services/coins/tezos/api/tezos_api.dart @@ -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?> 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 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 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; + } +} diff --git a/lib/services/coins/tezos/api/tezos_transaction.dart b/lib/services/coins/tezos/api/tezos_transaction.dart new file mode 100644 index 000000000..2c67fca6f --- /dev/null +++ b/lib/services/coins/tezos/api/tezos_transaction.dart @@ -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, + }); +} \ No newline at end of file diff --git a/lib/services/coins/tezos/tezos_api.dart b/lib/services/coins/tezos/tezos_api.dart deleted file mode 100644 index 1a4e8fca4..000000000 --- a/lib/services/coins/tezos/tezos_api.dart +++ /dev/null @@ -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>?> 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> 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 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; - } -} diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart index f28b14a38..ae25e5407 100644 --- a/lib/services/coins/tezos/tezos_wallet.dart +++ b/lib/services/coins/tezos/tezos_wallet.dart @@ -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 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 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 updateTransactions() async { - var txs = - await tezosAPI.getTransactions(walletId, await currentReceivingAddress); + List? 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> 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 updateChainHeight() async {