diff --git a/lib/models/isar/stack_theme.dart b/lib/models/isar/stack_theme.dart index 5809e4443..67fbb0ab7 100644 --- a/lib/models/isar/stack_theme.dart +++ b/lib/models/isar/stack_theme.dart @@ -1902,6 +1902,7 @@ class ThemeAssets implements IThemeAssets { late final String wownero; late final String namecoin; late final String particl; + late final String tezos; late final String bitcoinImage; late final String bitcoincashImage; late final String dogecoinImage; @@ -1913,6 +1914,7 @@ class ThemeAssets implements IThemeAssets { late final String wowneroImage; late final String namecoinImage; late final String particlImage; + late final String tezosImage; late final String bitcoinImageSecondary; late final String bitcoincashImageSecondary; late final String dogecoinImageSecondary; @@ -1924,6 +1926,7 @@ class ThemeAssets implements IThemeAssets { late final String wowneroImageSecondary; late final String namecoinImageSecondary; late final String particlImageSecondary; + late final String tezosImageSecondary; @override late final String? loadingGif; @override @@ -1997,6 +2000,8 @@ class ThemeAssets implements IThemeAssets { "$applicationThemesDirectoryPath/$themeId/assets/${json["namecoin"] as String}" ..particl = "$applicationThemesDirectoryPath/$themeId/assets/${json["particl"] as String}" + ..tezos = + "$applicationThemesDirectoryPath/$themeId/assets/${json["bitcoin"] as String}" // TODO: change to tezos ..bitcoinImage = "$applicationThemesDirectoryPath/$themeId/assets/${json["bitcoin_image"] as String}" ..bitcoincashImage = @@ -2019,6 +2024,8 @@ class ThemeAssets implements IThemeAssets { "$applicationThemesDirectoryPath/$themeId/assets/${json["namecoin_image"] as String}" ..particlImage = "$applicationThemesDirectoryPath/$themeId/assets/${json["particl_image"] as String}" + ..tezosImage = + "$applicationThemesDirectoryPath/$themeId/assets/${json["bitcoin_image"] as String}" // TODO: change to tezos ..bitcoinImageSecondary = "$applicationThemesDirectoryPath/$themeId/assets/${json["bitcoin_image_secondary"] as String}" ..bitcoincashImageSecondary = @@ -2041,6 +2048,8 @@ class ThemeAssets implements IThemeAssets { "$applicationThemesDirectoryPath/$themeId/assets/${json["namecoin_image_secondary"] as String}" ..particlImageSecondary = "$applicationThemesDirectoryPath/$themeId/assets/${json["particl_image_secondary"] as String}" + ..tezosImageSecondary = + "$applicationThemesDirectoryPath/$themeId/assets/${json["bitcoin_image_secondary"] as String}" // TODO: change to tezos ..loadingGif = json["loading_gif"] is String ? "$applicationThemesDirectoryPath/$themeId/assets/${json["loading_gif"] as String}" : null diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart index 1ff1a1359..b29f4718c 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart @@ -711,6 +711,7 @@ class _NodeFormState extends ConsumerState { case Coin.namecoin: case Coin.bitcoincash: case Coin.particl: + case Coin.tezos: case Coin.bitcoinTestNet: case Coin.litecoinTestNet: case Coin.bitcoincashTestnet: diff --git a/lib/services/coins/coin_service.dart b/lib/services/coins/coin_service.dart index 48fa59630..a6d1b023b 100644 --- a/lib/services/coins/coin_service.dart +++ b/lib/services/coins/coin_service.dart @@ -15,6 +15,7 @@ import 'package:stackwallet/services/coins/litecoin/litecoin_wallet.dart'; import 'package:stackwallet/services/coins/monero/monero_wallet.dart'; import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart'; import 'package:stackwallet/services/coins/particl/particl_wallet.dart'; +import 'package:stackwallet/services/coins/tezos/tezos_wallet.dart'; import 'package:stackwallet/services/coins/wownero/wownero_wallet.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; @@ -204,6 +205,15 @@ abstract class CoinServiceAPI { cachedClient: cachedClient, tracker: tracker); + case Coin.tezos: + return TezosWallet( + walletId: walletId, + walletName: walletName, + coin: coin, + secureStore: secureStorageInterface, + tracker: tracker, + ); + case Coin.wownero: return WowneroWallet( walletId: walletId, diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart new file mode 100644 index 000000000..9048c1d04 --- /dev/null +++ b/lib/services/coins/tezos/tezos_wallet.dart @@ -0,0 +1,410 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:ffi'; + +import 'package:http/http.dart'; +import 'package:isar/isar.dart'; +import 'package:stackwallet/models/balance.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart'; +import 'package:stackwallet/models/paymint/fee_object_model.dart'; +import 'package:stackwallet/services/coins/coin_service.dart'; +import 'package:stackwallet/services/node_service.dart'; +import 'package:stackwallet/utilities/amount/amount.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/default_nodes.dart'; +import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; + +import 'package:tezart/tezart.dart'; +import 'package:tuple/tuple.dart'; + +import '../../../db/isar/main_db.dart'; +import '../../../models/node_model.dart'; +import '../../../utilities/flutter_secure_storage_interface.dart'; +import '../../../utilities/logger.dart'; +import '../../../utilities/prefs.dart'; +import '../../mixins/wallet_cache.dart'; +import '../../mixins/wallet_db.dart'; +import '../../transaction_notification_tracker.dart'; + +const int MINIMUM_CONFIRMATIONS = 1; + +class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB { + TezosWallet({ + required String walletId, + required String walletName, + required Coin coin, + required SecureStorageInterface secureStore, + required TransactionNotificationTracker tracker, + MainDB? mockableOverride, + }) { + txTracker = tracker; + _walletId = walletId; + _walletName = walletName; + _coin = coin; + _secureStore = secureStore; + initCache(walletId, coin); + initWalletDB(mockableOverride: mockableOverride); + } + + NodeModel? _xtzNode; + + NodeModel getCurrentNode() { + return _xtzNode ?? NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: Coin.tezos) ?? DefaultNodes.getNodeFor(Coin.tezos); + } + + Future getKeystore() async { + return Keystore.fromMnemonic((await mnemonicString).toString()); + } + + @override + String get walletId => _walletId; + late String _walletId; + + @override + String get walletName => _walletName; + late String _walletName; + + @override + set walletName(String name) => _walletName = name; + + @override + set isFavorite(bool markFavorite) { + _isFavorite = markFavorite; + updateCachedIsFavorite(markFavorite); + } + + @override + bool get isFavorite => _isFavorite ??= getCachedIsFavorite(); + bool? _isFavorite; + + @override + Coin get coin => _coin; + late Coin _coin; + + late SecureStorageInterface _secureStore; + late final TransactionNotificationTracker txTracker; + final _prefs = Prefs.instance; + + Timer? timer; + bool _shouldAutoSync = false; + + @override + bool get shouldAutoSync => _shouldAutoSync; + + @override + set shouldAutoSync(bool shouldAutoSync) { + if (_shouldAutoSync != shouldAutoSync) { + _shouldAutoSync = shouldAutoSync; + if (!shouldAutoSync) { + timer?.cancel(); + timer = null; + } else { + refresh(); + } + } + } + + @override + Balance get balance => _balance ??= getCachedBalance(); + Balance? _balance; + + @override + Future> prepareSend({required String address, required Amount amount, Map? args}) async { + try { + if (amount.decimals != coin.decimals) { + throw Exception("Amount decimals do not match coin decimals!"); + } + var fee = int.parse((await estimateFeeFor(amount, (args!["feeRate"] as FeeRateType).index)).raw.toString()); + Map txData = { + "fee": fee, + "address": address, + "recipientAmt": amount, + }; + return Future.value(txData); + } catch (e) { + return Future.error(e); + } + } + + @override + Future confirmSend({required Map txData}) async { + try { + final node = getCurrentNode().host + getCurrentNode().port.toString(); + final int amountInMicroTez = ((int.parse((txData["recipientAmt"] as Amount).raw.toString()) * 1000000)).round(); + final int feeInMicroTez = int.parse(txData["fee"].toString()); + final String destinationAddress = txData["address"] as String; + final String sourceAddress = await currentReceivingAddress; + return Future.value(""); // TODO: return tx hash + } catch (e) { + Logging.instance.log(e.toString(), level: LogLevel.Error); + return Future.error(e); + } + } + + @override + Future get currentReceivingAddress async { + var mneString = await mnemonicString; + if (mneString == null) { + throw Exception("No mnemonic found!"); + } + return Future.value((Keystore.fromMnemonic(mneString)).address); + } + + @override + Future estimateFeeFor(Amount amount, int feeRate) { + return Future.value( + Amount(rawValue: BigInt.parse(100000.toString()), fractionDigits: coin.decimals), + ); + } + + @override + Future exit() { + _hasCalledExit = true; + return Future.value(); + } + + @override + Future get fees async { + // TODO: Change this to get fees from node and fix numberOfBlocks + return FeeObject( + numberOfBlocksFast: 1, + numberOfBlocksAverage: 1, + numberOfBlocksSlow: 1, + fast: 1000000, + medium: 100000, + slow: 10000, + ); + } + + @override + Future fullRescan(int maxUnusedAddressGap, int maxNumberOfIndexesToCheck) { + refresh(); + return Future.value(); + } + + @override + Future generateNewAddress() { + // TODO: implement generateNewAddress + throw UnimplementedError(); + } + + @override + bool get hasCalledExit => _hasCalledExit; + bool _hasCalledExit = false; + + @override + Future initializeExisting() async { + await _prefs.init(); + } + + @override + Future initializeNew() async { + var newKeystore = Keystore.random(); + await _secureStore.write( + key: '${_walletId}_mnemonic', + value: newKeystore.mnemonic, + ); + await _secureStore.write( + key: '${_walletId}_mnemonicPassphrase', + value: "", + ); + + final address = Address( + walletId: walletId, + value: newKeystore.address, + publicKey: [], // TODO: Add public key + derivationIndex: 0, + derivationPath: null, + type: AddressType.unknown, + subType: AddressSubType.unknown, + ); + + await db.putAddress(address); + + await Future.wait([ + updateCachedId(walletId), + updateCachedIsFavorite(false), + ]); + } + + @override + bool get isConnected => _isConnected; + bool _isConnected = false; + + @override + bool get isRefreshing => refreshMutex; + bool refreshMutex = false; + + @override + // TODO: implement maxFee + Future get maxFee => throw UnimplementedError(); + + @override + Future> get mnemonic async { + final mnemonic = await mnemonicString; + final mnemonicPassphrase = await this.mnemonicPassphrase; + if (mnemonic == null) { + throw Exception("No mnemonic found!"); + } + if (mnemonicPassphrase == null) { + throw Exception("No mnemonic passphrase found!"); + } + return mnemonic.split(" "); + } + + @override + Future get mnemonicPassphrase => _secureStore.read(key: '${_walletId}_mnemonicPassphrase'); + + @override + Future get mnemonicString => _secureStore.read(key: '${_walletId}_mnemonic'); + + @override + Future recoverFromMnemonic({required String mnemonic, String? mnemonicPassphrase, required int maxUnusedAddressGap, required int maxNumberOfIndexesToCheck, required int height}) async { + if ((await mnemonicString) != null || + (await this.mnemonicPassphrase) != null) { + throw Exception("Attempted to overwrite mnemonic on restore!"); + } + await _secureStore.write( + key: '${_walletId}_mnemonic', value: mnemonic.trim()); + await _secureStore.write( + key: '${_walletId}_mnemonicPassphrase', + value: mnemonicPassphrase ?? "", + ); + + final address = Address( + walletId: walletId, + value: Keystore.fromMnemonic(mnemonic).address, + publicKey: [], // TODO: Add public key + derivationIndex: 0, + derivationPath: null, + type: AddressType.unknown, + subType: AddressSubType.unknown, + ); + + await db.putAddress(address); + + await Future.wait([ + updateCachedId(walletId), + updateCachedIsFavorite(false), + ]); + } + + Future updateBalance() async { + var api = "https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/balance"; // TODO: Can we use current node instead of this? + var theBalance = await get(Uri.parse(api)).then((value) => value.body); + Logging.instance.log("Balance for ${await currentReceivingAddress}: $theBalance", level: LogLevel.Info); + var balanceInAmount = Amount(rawValue: BigInt.parse(theBalance.toString()), fractionDigits: 6); + _balance = Balance( + total: balanceInAmount, + spendable: balanceInAmount, + blockedTotal: Amount(rawValue: BigInt.parse("0"), fractionDigits: 6), + pendingSpendable: Amount(rawValue: BigInt.parse("0"), fractionDigits: 6), + ); + await updateCachedBalance(_balance!); + } + + Future updateTransactions() async { + var api = "https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/balance_history"; // TODO: Can we use current node instead of this? + var returnedTxs = await get(Uri.parse(api)).then((value) => value.body); + Logging.instance.log( + "Transactions for ${await currentReceivingAddress}: $returnedTxs", + level: LogLevel.Info); + List> txs = []; + Object? jsonTxs = jsonDecode(returnedTxs); + if (jsonTxs == null) { + await db.addNewTransactionData(txs, walletId); + } else { + for (var tx in jsonTxs as List) { + var theTx = Transaction( + walletId: walletId, + txid: "", + timestamp: DateTime.parse(tx["timestamp"].toString()).toUtc().millisecondsSinceEpoch ~/ 1000, + type: TransactionType.unknown, + subType: TransactionSubType.none, + amount: int.parse(tx["balance"].toString()), + amountString: Amount( + rawValue: BigInt.parse(tx["balance"].toString()), + fractionDigits: 6 + ).toJsonString(), + fee: 0, + height: int.parse(tx["level"].toString()), + isCancelled: false, + isLelantus: false, + slateId: "", + otherData: "", + inputs: [], + outputs: [], + nonce: 0 + ); + var theAddress = Address( + walletId: walletId, + value: await currentReceivingAddress, + publicKey: [], // TODO: Add public key + derivationIndex: 0, + derivationPath: null, + type: AddressType.unknown, + subType: AddressSubType.unknown, + ); + txs.add(Tuple2(theTx, theAddress)); + } + await db.addNewTransactionData(txs, walletId); + } + } + + Future updateChainHeight() async { + var api = "https://api.tzkt.io/v1/blocks/count"; // TODO: Can we use current node instead of this? + var returnedHeight = await get(Uri.parse(api)).then((value) => value.body); + final int intHeight = int.parse(returnedHeight.toString()); + await updateCachedChainHeight(intHeight); + } + + @override + Future refresh() { + updateChainHeight(); + updateBalance(); + updateTransactions(); + return Future.value(); + } + + @override + int get storedChainHeight => getCachedChainHeight(); + + @override + Future testNetworkConnection() async{ + try { + await get(Uri.parse("https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/balance")); + return true; + } catch (e) { + return false; + } + } + + @override + Future> get transactions => db.getTransactions(walletId).findAll(); + + @override + Future updateNode(bool shouldRefresh) async { + _xtzNode = NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: coin) ?? DefaultNodes.getNodeFor(coin); + + if (shouldRefresh) { + await refresh(); + } + } + + @override + Future updateSentCachedTxData(Map txData) { + // TODO: implement updateSentCachedTxData + throw UnimplementedError(); + } + + @override + // TODO: implement utxos + Future> get utxos => throw UnimplementedError(); + + @override + bool validateAddress(String address) { + return RegExp(r"^tz[1-9A-HJ-NP-Za-km-z]{34}$").hasMatch(address); + } +} diff --git a/lib/themes/coin_icon_provider.dart b/lib/themes/coin_icon_provider.dart index 6c17969e6..3792560e6 100644 --- a/lib/themes/coin_icon_provider.dart +++ b/lib/themes/coin_icon_provider.dart @@ -35,6 +35,8 @@ final coinIconProvider = Provider.family((ref, coin) { return assets.namecoin; case Coin.particl: return assets.particl; + case Coin.tezos: + return assets.tezos; case Coin.ethereum: return assets.ethereum; } diff --git a/lib/themes/coin_image_provider.dart b/lib/themes/coin_image_provider.dart index 239e1d1cb..3de9ab40a 100644 --- a/lib/themes/coin_image_provider.dart +++ b/lib/themes/coin_image_provider.dart @@ -31,6 +31,8 @@ final coinImageProvider = Provider.family((ref, coin) { return assets.namecoinImage; case Coin.particl: return assets.particlImage; + case Coin.tezos: + return assets.tezosImage; case Coin.bitcoinTestNet: return assets.bitcoinImage; case Coin.bitcoincashTestnet: @@ -75,6 +77,8 @@ final coinImageSecondaryProvider = Provider.family((ref, coin) { return assets.namecoinImageSecondary; case Coin.particl: return assets.particlImageSecondary; + case Coin.tezos: + return assets.tezosImageSecondary; case Coin.bitcoinTestNet: return assets.bitcoinImageSecondary; case Coin.bitcoincashTestnet: diff --git a/lib/themes/color_theme.dart b/lib/themes/color_theme.dart index b4f00adcf..7946139c3 100644 --- a/lib/themes/color_theme.dart +++ b/lib/themes/color_theme.dart @@ -18,6 +18,7 @@ class CoinThemeColorDefault { Color get namecoin => const Color(0xFF91B1E1); Color get wownero => const Color(0xFFED80C1); Color get particl => const Color(0xFF8175BD); + Color get tezos => const Color(0xFF0F61FF); Color forCoin(Coin coin) { switch (coin) { @@ -50,6 +51,8 @@ class CoinThemeColorDefault { return wownero; case Coin.particl: return particl; + case Coin.tezos: + return tezos; } } } diff --git a/lib/themes/stack_colors.dart b/lib/themes/stack_colors.dart index 6717615b1..8f5dbbe15 100644 --- a/lib/themes/stack_colors.dart +++ b/lib/themes/stack_colors.dart @@ -1697,6 +1697,8 @@ class StackColors extends ThemeExtension { return _coin.wownero; case Coin.particl: return _coin.particl; + case Coin.tezos: + return _coin.tezos; } } diff --git a/lib/utilities/address_utils.dart b/lib/utilities/address_utils.dart index 44850bc65..a151abbdf 100644 --- a/lib/utilities/address_utils.dart +++ b/lib/utilities/address_utils.dart @@ -74,6 +74,8 @@ class AddressUtils { return Address.validateAddress(address, namecoin, namecoin.bech32!); case Coin.particl: return Address.validateAddress(address, particl); + case Coin.tezos: + return RegExp(r"^tz[1-9A-HJ-NP-Za-km-z]{34}$").hasMatch(address); case Coin.bitcoinTestNet: return Address.validateAddress(address, testnet); case Coin.litecoinTestNet: diff --git a/lib/utilities/block_explorers.dart b/lib/utilities/block_explorers.dart index cf0628fd2..4f4228e27 100644 --- a/lib/utilities/block_explorers.dart +++ b/lib/utilities/block_explorers.dart @@ -43,6 +43,8 @@ Uri getDefaultBlockExplorerUrlFor({ return Uri.parse("https://chainz.cryptoid.info/nmc/tx.dws?$txid.htm"); case Coin.particl: return Uri.parse("https://chainz.cryptoid.info/part/tx.dws?$txid.htm"); + case Coin.tezos: + return Uri.parse("https://tzstats.com/$txid"); } } diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart index b3295b3c8..b74de5b98 100644 --- a/lib/utilities/constants.dart +++ b/lib/utilities/constants.dart @@ -29,12 +29,14 @@ abstract class Constants { static const int _satsPerCoinECash = 100; static const int _satsPerCoinMonero = 1000000000000; static const int _satsPerCoinWownero = 100000000000; + static const int _satsPerCoinTezos = 1000000; static const int _satsPerCoin = 100000000; static const int _decimalPlaces = 8; static const int _decimalPlacesWownero = 11; static const int _decimalPlacesMonero = 12; static const int _decimalPlacesEthereum = 18; static const int _decimalPlacesECash = 2; + static const int _decimalPlacesTezos = 6; static const int notificationsMax = 0xFFFFFFFF; static const Duration networkAliveTimerDuration = Duration(seconds: 10); @@ -76,6 +78,9 @@ abstract class Constants { case Coin.eCash: return _satsPerCoinECash; + + case Coin.tezos: + return _satsPerCoinTezos; } } @@ -107,6 +112,9 @@ abstract class Constants { case Coin.eCash: return _decimalPlacesECash; + + case Coin.tezos: + return _decimalPlacesTezos; } } @@ -128,6 +136,7 @@ abstract class Constants { case Coin.ethereum: case Coin.namecoin: case Coin.particl: + case Coin.tezos: values.addAll([24, 21, 18, 15, 12]); break; @@ -180,6 +189,9 @@ abstract class Constants { case Coin.particl: return 600; + + case Coin.tezos: + return 60; } } diff --git a/lib/utilities/default_nodes.dart b/lib/utilities/default_nodes.dart index 0f8425c88..ad9310c3d 100644 --- a/lib/utilities/default_nodes.dart +++ b/lib/utilities/default_nodes.dart @@ -169,7 +169,20 @@ abstract class DefaultNodes { enabled: true, coinName: Coin.particl.name, isFailover: true, - isDown: false); + isDown: false + ); + + static NodeModel get tezos => NodeModel( // TODO: Change this to original one + host: "mainnet.api.tez.ie", + port: 443, + name: defaultName, + id: _nodeId(Coin.tezos), + useSSL: true, + enabled: true, + coinName: Coin.tezos.name, + isFailover: true, + isDown: false + ); static NodeModel get bitcoinTestnet => NodeModel( host: "bitcoin-testnet.stackwallet.com", @@ -269,6 +282,9 @@ abstract class DefaultNodes { case Coin.particl: return particl; + case Coin.tezos: + return tezos; + case Coin.bitcoinTestNet: return bitcoinTestnet; diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart index f1109a626..096e26db5 100644 --- a/lib/utilities/enums/coin_enum.dart +++ b/lib/utilities/enums/coin_enum.dart @@ -16,6 +16,7 @@ import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart' as nmc; import 'package:stackwallet/services/coins/particl/particl_wallet.dart' as particl; +import 'package:stackwallet/services/coins/tezos/tezos_wallet.dart' as tezos; import 'package:stackwallet/services/coins/wownero/wownero_wallet.dart' as wow; import 'package:stackwallet/utilities/constants.dart'; @@ -31,6 +32,7 @@ enum Coin { monero, namecoin, particl, + tezos, wownero, /// @@ -71,6 +73,8 @@ extension CoinExt on Coin { return "Monero"; case Coin.particl: return "Particl"; + case Coin.tezos: + return "Tezos"; case Coin.wownero: return "Wownero"; case Coin.namecoin: @@ -110,6 +114,8 @@ extension CoinExt on Coin { return "XMR"; case Coin.particl: return "PART"; + case Coin.tezos: + return "XTZ"; case Coin.wownero: return "WOW"; case Coin.namecoin: @@ -150,6 +156,8 @@ extension CoinExt on Coin { return "monero"; case Coin.particl: return "particl"; + case Coin.tezos: + return "tezos"; case Coin.wownero: return "wownero"; case Coin.namecoin: @@ -187,6 +195,7 @@ extension CoinExt on Coin { case Coin.epicCash: case Coin.ethereum: case Coin.monero: + case Coin.tezos: case Coin.wownero: return false; } @@ -207,6 +216,7 @@ extension CoinExt on Coin { case Coin.eCash: case Coin.epicCash: case Coin.monero: + case Coin.tezos: case Coin.wownero: case Coin.dogecoinTestNet: case Coin.bitcoinTestNet: @@ -229,6 +239,7 @@ extension CoinExt on Coin { case Coin.epicCash: case Coin.ethereum: case Coin.monero: + case Coin.tezos: case Coin.wownero: case Coin.eCash: return false; @@ -254,6 +265,7 @@ extension CoinExt on Coin { case Coin.epicCash: case Coin.ethereum: case Coin.monero: + case Coin.tezos: case Coin.wownero: case Coin.eCash: return this; @@ -312,6 +324,9 @@ extension CoinExt on Coin { case Coin.particl: return particl.MINIMUM_CONFIRMATIONS; + case Coin.tezos: + return tezos.MINIMUM_CONFIRMATIONS; + case Coin.wownero: return wow.MINIMUM_CONFIRMATIONS; @@ -367,6 +382,10 @@ Coin coinFromPrettyName(String name) { case "particl": return Coin.particl; + case "Tezos": + case "tezos": + return Coin.tezos; + case "Namecoin": case "namecoin": return Coin.namecoin; @@ -436,6 +455,8 @@ Coin coinFromTickerCaseInsensitive(String ticker) { return Coin.namecoin; case "part": return Coin.particl; + case "xtz": + return Coin.tezos; case "tltc": return Coin.litecoinTestNet; case "tbtc": diff --git a/lib/utilities/enums/derive_path_type_enum.dart b/lib/utilities/enums/derive_path_type_enum.dart index 72899f5bd..315a355db 100644 --- a/lib/utilities/enums/derive_path_type_enum.dart +++ b/lib/utilities/enums/derive_path_type_enum.dart @@ -37,6 +37,7 @@ extension DerivePathTypeExt on DerivePathType { case Coin.epicCash: case Coin.monero: case Coin.wownero: + case Coin.tezos: // TODO: Is this true? throw UnsupportedError( "$coin does not use bitcoin style derivation paths"); } diff --git a/pubspec.lock b/pubspec.lock index 600a92d67..14c0aca59 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8" + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a url: "https://pub.dev" source: hosted - version: "47.0.0" + version: "61.0.0" analyzer: dependency: "direct dev" description: name: analyzer - sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80" + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "5.13.0" animations: dependency: "direct main" description: @@ -33,6 +33,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.12.29" + ansicolor: + dependency: transitive + description: + name: ansicolor + sha256: "607f8fa9786f392043f169898923e6c59b4518242b68b8862eb8a8b7d9c30b4a" + url: "https://pub.dev" + source: hosted + version: "2.0.1" app_settings: dependency: "direct main" description: @@ -490,6 +498,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.5" + dio: + dependency: transitive + description: + name: dio + sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8" + url: "https://pub.dev" + source: hosted + version: "4.0.6" dropdown_button2: dependency: "direct main" description: @@ -966,6 +982,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.2" + json_serializable: + dependency: transitive + description: + name: json_serializable + sha256: dadc08bd61f72559f938dd08ec20dbfec6c709bba83515085ea943d2078d187a + url: "https://pub.dev" + source: hosted + version: "6.6.1" jsonrpc2: dependency: "direct main" description: @@ -1037,6 +1061,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.0" + memoize: + dependency: transitive + description: + name: memoize + sha256: "51481d328c86cbdc59711369179bac88551ca0556569249be5317e66fc796cac" + url: "https://pub.dev" + source: hosted + version: "3.0.0" meta: dependency: transitive description: @@ -1285,6 +1317,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.1.0" + pinenacl: + dependency: transitive + description: + name: pinenacl + sha256: e5fb0bce1717b7f136f35ee98b5c02b3e6383211f8a77ca882fa7812232a07b9 + url: "https://pub.dev" + source: hosted + version: "0.3.4" platform: dependency: transitive description: @@ -1317,6 +1357,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + pretty_dio_logger: + dependency: transitive + description: + name: pretty_dio_logger + sha256: "948f7eeb36e7aa0760b51c1a8e3331d4b21e36fabd39efca81f585ed93893544" + url: "https://pub.dev" + source: hosted + version: "1.2.0-beta-1" process: dependency: transitive description: @@ -1365,6 +1413,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + quiver: + dependency: transitive + description: + name: quiver + sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 + url: "https://pub.dev" + source: hosted + version: "3.2.1" rational: dependency: "direct main" description: @@ -1373,6 +1429,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.2" + retry: + dependency: transitive + description: + name: retry + sha256: a8a1e475a100a0bdc73f529ca8ea1e9c9c76bec8ad86a1f47780139a34ce7aea + url: "https://pub.dev" + source: hosted + version: "3.1.1" riverpod: dependency: transitive description: @@ -1659,6 +1723,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.20" + tezart: + dependency: "direct main" + description: + name: tezart + sha256: "35d526f2e6ca250c64461ebfb4fa9f64b6599fab8c4242c8e89ae27d4ac2e15a" + url: "https://pub.dev" + source: hosted + version: "2.0.5" time: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3533282bf..25cd1e354 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -153,6 +153,7 @@ dependencies: rational: ^2.2.2 archive: ^3.3.2 desktop_drop: ^0.4.1 + tezart: ^2.0.5 dev_dependencies: flutter_test: @@ -198,6 +199,7 @@ dependency_overrides: url: https://github.com/cypherstack/stack-bip39.git ref: 3bef5acc21340f3cc78df0ad1dce5868a3ed68a5 crypto: 3.0.2 + analyzer: ^5.2.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec