diff --git a/assets/images/thorchain.png b/assets/images/thorchain.png new file mode 100644 index 000000000..674b60f82 Binary files /dev/null and b/assets/images/thorchain.png differ diff --git a/lib/di.dart b/lib/di.dart index 61a04bf1c..222ac037a 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -231,6 +231,7 @@ import 'package:cake_wallet/entities/qr_view_data.dart'; import 'buy/dfx/dfx_buy_provider.dart'; import 'core/totp_request_details.dart'; +import 'exchange/provider/thorchain_exchange.provider.dart'; import 'src/screens/settings/desktop_settings/desktop_settings_page.dart'; final getIt = GetIt.instance; @@ -1194,5 +1195,7 @@ Future setup({ getIt.registerFactory(() => NFTViewModel(appStore, getIt.get())); getIt.registerFactory(() => TorPage(getIt.get())); + getIt.registerFactory(() => ThorChainExchangeProvider(tradesStore: tradesSource)); + _isSetupFinished = true; } diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart index 2d5e64817..13b2fe8ae 100644 --- a/lib/entities/preferences_key.dart +++ b/lib/entities/preferences_key.dart @@ -96,4 +96,5 @@ class PreferencesKey { static const selectedCake2FAPreset = 'selected_cake_2fa_preset'; static const totpSecretKey = 'totp_secret_key'; static const currentSeedPhraseLength = 'current_seed_phrase_length'; + static const thorChainTradeCounter = 'thor_chain_trade_counter'; } diff --git a/lib/exchange/exchange_provider_description.dart b/lib/exchange/exchange_provider_description.dart index 6d141cb54..fab35537a 100644 --- a/lib/exchange/exchange_provider_description.dart +++ b/lib/exchange/exchange_provider_description.dart @@ -23,7 +23,7 @@ class ExchangeProviderDescription extends EnumerableItem with Serializable< static const exolix = ExchangeProviderDescription(title: 'Exolix', raw: 6, image: 'assets/images/exolix.png'); static const thorChain = - ExchangeProviderDescription(title: 'ThorChain', raw: 7, image: 'assets/images/exolix.png'); + ExchangeProviderDescription(title: 'ThorChain' , raw: 7, image: 'assets/images/thorchain.png'); static const all = ExchangeProviderDescription(title: 'All trades', raw: 8, image: ''); diff --git a/lib/exchange/provider/thorchain_exchange.provider.dart b/lib/exchange/provider/thorchain_exchange.provider.dart index ea8abc5d9..ca000baa2 100644 --- a/lib/exchange/provider/thorchain_exchange.provider.dart +++ b/lib/exchange/provider/thorchain_exchange.provider.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/exchange/exchange_provider_description.dart'; import 'package:cake_wallet/exchange/limits.dart'; import 'package:cake_wallet/exchange/provider/exchange_provider.dart'; @@ -7,12 +8,17 @@ import 'package:cake_wallet/exchange/trade.dart'; import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; +import 'package:cake_wallet/store/dashboard/trades_store.dart'; import 'package:cw_core/amount_converter.dart'; import 'package:cw_core/crypto_currency.dart'; +import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:collection/collection.dart'; class ThorChainExchangeProvider extends ExchangeProvider { - ThorChainExchangeProvider() : super(pairList: supportedPairs(_notSupported)); + ThorChainExchangeProvider({required this.tradesStore}) + : super(pairList: supportedPairs(_notSupported)); static final List _notSupported = [ ...(CryptoCurrency.all @@ -30,6 +36,8 @@ class ThorChainExchangeProvider extends ExchangeProvider { static const _affiliateName = 'cakewallet'; static const _affiliateBps = '0'; + final Box tradesStore; + @override String get title => 'ThorChain'; @@ -96,22 +104,22 @@ class ThorChainExchangeProvider extends ExchangeProvider { 'amount': formattedAmount, 'destination': request.toAddress, 'affiliate': _affiliateName, - 'affiliate_bps': _affiliateBps}; + 'affiliate_bps': _affiliateBps + }; final responseJSON = await _getSwapQuote(params); print('createTrade _ responseJSON________: $responseJSON'); final inputAddress = responseJSON['inbound_address'] as String?; final memo = responseJSON['memo'] as String?; + final tradeId = await getNextTradeCounter(); return Trade( - id: 'id', + id: tradeId.toString(), from: request.fromCurrency, to: request.toCurrency, provider: description, inputAddress: inputAddress, - refundAddress: 'refundAddress', - extraId: 'extraId', createdAt: DateTime.now(), amount: request.fromAmount, state: TradeState.created, @@ -156,9 +164,12 @@ class ThorChainExchangeProvider extends ExchangeProvider { } } - @override - Future findTradeById({required String id}) { - throw UnimplementedError('findTradeById'); + Future findTradeById({required String id}) async { + final foundTrade = tradesStore.values.firstWhereOrNull((element) => element.id == id); + if (foundTrade == null) { + throw Exception('Trade with id $id not found'); + } + return foundTrade; } String _normalizeCurrency(CryptoCurrency currency) { @@ -175,4 +186,12 @@ class ThorChainExchangeProvider extends ExchangeProvider { return currency.title.toLowerCase(); } } + + Future getNextTradeCounter() async { + final prefs = await SharedPreferences.getInstance(); + int currentCounter = prefs.getInt(PreferencesKey.thorChainTradeCounter) ?? 0; + currentCounter++; + await prefs.setInt(PreferencesKey.thorChainTradeCounter, currentCounter); + return currentCounter; + } } diff --git a/lib/src/screens/dashboard/widgets/trade_row.dart b/lib/src/screens/dashboard/widgets/trade_row.dart index 7f570b98e..caccb8047 100644 --- a/lib/src/screens/dashboard/widgets/trade_row.dart +++ b/lib/src/screens/dashboard/widgets/trade_row.dart @@ -34,7 +34,9 @@ class TradeRow extends StatelessWidget { mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _getPoweredImage(provider)!, + ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Image.asset(provider.image, width: 36, height: 36)), SizedBox(width: 12), Expanded( child: Column( @@ -69,38 +71,4 @@ class TradeRow extends StatelessWidget { ), )); } - - Widget? _getPoweredImage(ExchangeProviderDescription provider) { - Widget? image; - - switch (provider) { - case ExchangeProviderDescription.xmrto: - image = Image.asset('assets/images/xmrto.png', height: 36, width: 36); - break; - case ExchangeProviderDescription.changeNow: - image = Image.asset('assets/images/changenow.png', height: 36, width: 36); - break; - case ExchangeProviderDescription.morphToken: - image = Image.asset('assets/images/morph.png', height: 36, width: 36); - break; - case ExchangeProviderDescription.sideShift: - image = Image.asset('assets/images/sideshift.png', width: 36, height: 36); - break; - case ExchangeProviderDescription.simpleSwap: - image = Image.asset('assets/images/simpleSwap.png', width: 36, height: 36); - break; - case ExchangeProviderDescription.trocador: - image = ClipRRect( - borderRadius: BorderRadius.circular(50), - child: Image.asset('assets/images/trocador.png', width: 36, height: 36)); - break; - case ExchangeProviderDescription.exolix: - image = Image.asset('assets/images/exolix.png', width: 36, height: 36); - break; - default: - image = null; - } - - return image; - } } diff --git a/lib/src/screens/exchange/exchange_page.dart b/lib/src/screens/exchange/exchange_page.dart index b3fbd19a7..76b1596ac 100644 --- a/lib/src/screens/exchange/exchange_page.dart +++ b/lib/src/screens/exchange/exchange_page.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/exchange/exchange_provider_description.dart'; import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart'; import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/core/auth_service.dart'; @@ -431,7 +432,9 @@ class ExchangePage extends BasePage { } if (state is TradeIsCreatedSuccessfully) { exchangeViewModel.reset(); - Navigator.of(context).pushNamed(Routes.exchangeConfirm); + (exchangeViewModel.tradesStore.trade?.provider == ExchangeProviderDescription.thorChain) + ? Navigator.of(context).pushReplacementNamed(Routes.exchangeTrade) + : Navigator.of(context).pushReplacementNamed(Routes.exchangeConfirm); } }); diff --git a/lib/view_model/exchange/exchange_trade_view_model.dart b/lib/view_model/exchange/exchange_trade_view_model.dart index b85776f71..687d87f80 100644 --- a/lib/view_model/exchange/exchange_trade_view_model.dart +++ b/lib/view_model/exchange/exchange_trade_view_model.dart @@ -49,7 +49,7 @@ abstract class ExchangeTradeViewModelBase with Store { _provider = ExolixExchangeProvider(); break; case ExchangeProviderDescription.thorChain: - _provider = ThorChainExchangeProvider(); + _provider = ThorChainExchangeProvider(tradesStore: trades); break; } diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index f96bd39f0..831141987 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -148,7 +148,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with SimpleSwapExchangeProvider(), TrocadorExchangeProvider(useTorOnly: _useTorOnly, providerStates: _settingsStore.trocadorProviderStates), - ThorChainExchangeProvider(), + ThorChainExchangeProvider(tradesStore: trades), if (FeatureFlag.isExolixEnabled) ExolixExchangeProvider(), ]; diff --git a/lib/view_model/trade_details_view_model.dart b/lib/view_model/trade_details_view_model.dart index f5aa2122a..2a0733ed7 100644 --- a/lib/view_model/trade_details_view_model.dart +++ b/lib/view_model/trade_details_view_model.dart @@ -54,7 +54,7 @@ abstract class TradeDetailsViewModelBase with Store { _provider = ExolixExchangeProvider(); break; case ExchangeProviderDescription.thorChain: - _provider = ThorChainExchangeProvider(); + _provider = ThorChainExchangeProvider(tradesStore: trades); break; } @@ -66,6 +66,24 @@ abstract class TradeDetailsViewModelBase with Store { } } + static String? getTrackUrl(ExchangeProviderDescription provider, Trade trade) { + switch (provider) { + case ExchangeProviderDescription.changeNow: + return 'https://changenow.io/exchange/txs/${trade.id}'; + case ExchangeProviderDescription.sideShift: + return 'https://sideshift.ai/orders/${trade.id}'; + case ExchangeProviderDescription.simpleSwap: + return 'https://simpleswap.io/exchange?id=${trade.id}'; + case ExchangeProviderDescription.trocador: + return 'https://trocador.app/en/checkout/${trade.id}'; + case ExchangeProviderDescription.exolix: + return 'https://exolix.com/transaction/${trade.id}'; + case ExchangeProviderDescription.thorChain: + return 'https://track.ninerealms.com/${trade.id}'; + } + return null; + } + final Box trades; @observable @@ -129,46 +147,22 @@ abstract class TradeDetailsViewModelBase with Store { items.add(StandartListItem( title: S.current.trade_details_provider, value: trade.provider.toString())); - if (trade.provider == ExchangeProviderDescription.changeNow) { - final buildURL = 'https://changenow.io/exchange/txs/${trade.id.toString()}'; - items.add(TrackTradeListItem( - title: 'Track', - value: buildURL, - onTap: () { - _launchUrl(buildURL); - })); - } - - if (trade.provider == ExchangeProviderDescription.sideShift) { - final buildURL = 'https://sideshift.ai/orders/${trade.id.toString()}'; + final trackUrl = TradeDetailsViewModelBase.getTrackUrl(trade.provider, trade); + if (trackUrl != null) { items.add( - TrackTradeListItem(title: 'Track', value: buildURL, onTap: () => _launchUrl(buildURL))); - } - - if (trade.provider == ExchangeProviderDescription.simpleSwap) { - final buildURL = 'https://simpleswap.io/exchange?id=${trade.id.toString()}'; - items.add( - TrackTradeListItem(title: 'Track', value: buildURL, onTap: () => _launchUrl(buildURL))); + TrackTradeListItem(title: 'Track', value: trackUrl,onTap: () => _launchUrl(trackUrl))); } if (trade.provider == ExchangeProviderDescription.trocador) { - final buildURL = 'https://trocador.app/en/checkout/${trade.id.toString()}'; - items.add( - TrackTradeListItem(title: 'Track', value: buildURL, onTap: () => _launchUrl(buildURL))); - items.add(StandartListItem( title: '${trade.providerName} ${S.current.id.toUpperCase()}', value: trade.providerId ?? '')); - if (trade.password != null && trade.password!.isNotEmpty) + if (trade.password != null && trade.password!.isNotEmpty) { items.add(StandartListItem( - title: '${trade.providerName} ${S.current.password}', value: trade.password ?? '')); - } - - if (trade.provider == ExchangeProviderDescription.exolix) { - final buildURL = 'https://exolix.com/transaction/${trade.id.toString()}'; - items.add( - TrackTradeListItem(title: 'Track', value: buildURL, onTap: () => _launchUrl(buildURL))); + title: '${trade.providerName} ${S.current.password}', + value: trade.password ?? '')); + } } }