diff --git a/assets/icons/chart.bar.svg b/assets/icons/chart.bar.svg new file mode 100644 index 0000000..70d2aee --- /dev/null +++ b/assets/icons/chart.bar.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/assets/icons/checkmark.circle.fill.svg b/assets/icons/checkmark.circle.fill.svg new file mode 100644 index 0000000..edb9145 --- /dev/null +++ b/assets/icons/checkmark.circle.fill.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/assets/icons/document.on.document.svg b/assets/icons/document.on.document.svg new file mode 100644 index 0000000..c0ddb1c --- /dev/null +++ b/assets/icons/document.on.document.svg @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/assets/logos/dexscreener.svg b/assets/logos/dexscreener.svg new file mode 100644 index 0000000..f26fca9 --- /dev/null +++ b/assets/logos/dexscreener.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/lib/app/app_layout.dart b/lib/app/app_layout.dart index b568aa8..96d6994 100644 --- a/lib/app/app_layout.dart +++ b/lib/app/app_layout.dart @@ -48,25 +48,24 @@ class _AppPageState extends State with DeviceInfoMixin { if (cache.getCookiesConsentStatus() == null) Overlay.of(context).insert(overlayEntry); - ScaffoldMessenger.of(context).showMaterialBanner( - MaterialBanner( - backgroundColor: ZupColors.orange6, - padding: const EdgeInsets.only(left: 20, right: 10, bottom: 5, top: 5), - dividerColor: Colors.transparent, - content: const Text( - "⚠️ 24h and 7d Yields on Base Network are temporarily delayed, we’re on it! 🚧 30d, and 90d Yields are still running fine.", - style: TextStyle(color: ZupColors.orange), - ), - actions: [ - ZupIconButton( - iconColor: ZupColors.orange, - backgroundColor: ZupColors.orange5, - icon: const Icon(Icons.close), - onPressed: (context) => ScaffoldMessenger.of(context).clearMaterialBanners(), - ), - ], - ), - ); + // ScaffoldMessenger.of(context).showMaterialBanner( + // MaterialBanner( + // backgroundColor: ZupColors.orange6, + // padding: const EdgeInsets.only(left: 20, right: 10, bottom: 5, top: 5), + // dividerColor: Colors.transparent, + // content: const Text( + // "⚠️ 24h Yields on Base Network are temporarily delayed, we’re on it! 🚧 7d, 30d, and 90d Yields are still running fine.", + // style: TextStyle(color: ZupColors.orange), + // ), + // actions: [ + // ZupIconButton( + // backgroundColor: ZupColors.orange5, + // icon: const Icon(Icons.close, color: ZupColors.orange), + // onPressed: (context) => ScaffoldMessenger.of(context).clearMaterialBanners(), + // ), + // ], + // ), + // ); }); } @@ -77,27 +76,29 @@ class _AppPageState extends State with DeviceInfoMixin { backgroundColor: ZupThemeColors.background.themed(context.brightness), bottomNavigationBar: shouldShowBottomNavigationBar ? const AppBottomNavigationBar() : null, extendBody: shouldShowBottomNavigationBar, - body: CustomScrollView( + body: PrimaryScrollController( controller: appScrollController, - shrinkWrap: true, - physics: const ClampingScrollPhysics(), - slivers: [ - SliverAppBar( - clipBehavior: Clip.none, - forceMaterialTransparency: true, - pinned: true, - titleSpacing: 0, - title: AppHeader(height: appBarHeight), - toolbarHeight: appBarHeight, - ), - const SliverFillRemaining(hasScrollBody: false, child: RouterOutlet(key: Key("screen"))), - SliverToBoxAdapter( - child: Padding( - padding: EdgeInsets.only(bottom: shouldShowBottomNavigationBar ? AppBottomNavigationBar.height : 0), - child: const AppFooter(), + child: CustomScrollView( + primary: true, + physics: const ClampingScrollPhysics(), + slivers: [ + SliverAppBar( + clipBehavior: Clip.none, + forceMaterialTransparency: true, + pinned: true, + titleSpacing: 0, + title: AppHeader(height: appBarHeight), + toolbarHeight: appBarHeight, ), - ), - ], + const SliverFillRemaining(hasScrollBody: false, child: RouterOutlet(key: Key("screen"))), + SliverToBoxAdapter( + child: Padding( + padding: EdgeInsets.only(bottom: shouldShowBottomNavigationBar ? AppBottomNavigationBar.height : 0), + child: const AppFooter(), + ), + ), + ], + ), ), ), ); diff --git a/lib/app/create/create_page_select_tokens_stage.dart b/lib/app/create/create_page_select_tokens_stage.dart index 98f302d..c7e8587 100644 --- a/lib/app/create/create_page_select_tokens_stage.dart +++ b/lib/app/create/create_page_select_tokens_stage.dart @@ -6,7 +6,7 @@ import 'package:zup_app/app/app_cubit/app_cubit.dart'; import 'package:zup_app/app/create/widgets/create_page_settings_dropdown/create_page_settings_dropdown.dart'; import 'package:zup_app/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button.dart'; import 'package:zup_app/core/cache.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/core/zup_navigator.dart'; import 'package:zup_app/gen/assets.gen.dart'; @@ -35,7 +35,7 @@ class _CreatePageState extends State with DeviceInf StreamSubscription? _token1SelectorStreamSubscription; StreamSubscription? _selectedNetworkStreamSubscription; - bool areTokensEqual(TokenDto? token0, TokenDto? token1) { + bool areTokensEqual(MultiChainTokenDto? token0, MultiChainTokenDto? token1) { if (token0 == null || token1 == null) return false; if (appCubit.selectedNetwork.isAllNetworks) return token0.internalId == token1.internalId; diff --git a/lib/app/create/widgets/create_page_settings_dropdown/create_page_settings_dropdown.dart b/lib/app/create/widgets/create_page_settings_dropdown/create_page_settings_dropdown.dart index 1f1aff3..eff91cf 100644 --- a/lib/app/create/widgets/create_page_settings_dropdown/create_page_settings_dropdown.dart +++ b/lib/app/create/widgets/create_page_settings_dropdown/create_page_settings_dropdown.dart @@ -163,65 +163,6 @@ class _CreatePageSettingsDropdownState extends State ) : const SizedBox.shrink(), ), - const SizedBox(height: 10), - Row( - children: [ - sectionTitle(S.of(context).createPageSettingsDropdownAllowedPoolTypes), - const SizedBox(width: 8), - ZupTooltip.text( - key: const Key("pool-types-allowed-tooltip"), - message: S.of(context).createPageSettingsDropdownAllowedPoolTypesDescription, - child: Assets.icons.infoCircle.svg( - colorFilter: const ColorFilter.mode(ZupColors.gray, BlendMode.srcIn), - ), - ), - ], - ), - const SizedBox(height: 5), - Row( - children: [ - Text( - "V4", - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 15, - color: ZupThemeColors.primaryText.themed(context.brightness), - ), - ), - const SizedBox(width: 5), - ZupSwitch( - key: const Key("pool-types-allowed-v4-switch"), - value: cache.getPoolSearchSettings().allowV4Search, - onChanged: (value) async { - await cache.savePoolSearchSettings( - settings: cache.getPoolSearchSettings().copyWith(allowV4Search: value), - ); - - setState(() {}); - }, - ), - const SizedBox(width: 12), - Text( - "V3", - style: TextStyle( - fontWeight: FontWeight.w500, - color: ZupThemeColors.primaryText.themed(context.brightness), - ), - ), - const SizedBox(width: 5), - ZupSwitch( - key: const Key("pool-types-allowed-v3-switch"), - value: cache.getPoolSearchSettings().allowV3Search, - onChanged: (value) async { - await cache.savePoolSearchSettings( - settings: cache.getPoolSearchSettings().copyWith(allowV3Search: value), - ); - - setState(() {}); - }, - ), - ], - ), ], ), ); diff --git a/lib/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button.dart b/lib/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button.dart index 8386ef6..9c4faf3 100644 --- a/lib/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button.dart +++ b/lib/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button.dart @@ -6,7 +6,6 @@ import 'package:zup_app/core/injections.dart'; import 'package:zup_app/core/repositories/protocol_repository.dart'; import 'package:zup_app/gen/assets.gen.dart'; import 'package:zup_app/l10n/gen/app_localizations.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; import 'package:zup_core/extensions/extensions.dart'; import 'package:zup_core/zup_singleton_cache.dart'; import 'package:zup_ui_kit/zup_ui_kit.dart'; @@ -21,7 +20,7 @@ class ExchangesFilterDropdownButton extends StatefulWidget { class _ExchangesFilterDropdownButtonState extends State { final zupSingletonCache = inject(); final protocolRepository = inject(); - final zupCachedImage = inject(); + final zupNetworkImage = inject(); final cache = inject(); ExchangesFilterDropdownButtonCubit? cubit; @@ -114,7 +113,7 @@ class _ExchangesFilterDropdownButtonState extends State ZupCheckboxItem( id: protocol.rawId, title: protocol.name, - icon: zupCachedImage.build( + icon: zupNetworkImage.load( context, protocol.logo, radius: 20, diff --git a/lib/app/create/yields/[id]/deposit/deposit_cubit.dart b/lib/app/create/yields/[id]/deposit/deposit_cubit.dart index 63aedab..84b51b6 100644 --- a/lib/app/create/yields/[id]/deposit/deposit_cubit.dart +++ b/lib/app/create/yields/[id]/deposit/deposit_cubit.dart @@ -7,8 +7,8 @@ import 'package:zup_app/core/cache.dart'; import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_conversors_mixin.dart'; import 'package:zup_app/core/dtos/deposit_page_arguments_dto.dart'; import 'package:zup_app/core/dtos/deposit_settings_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; import 'package:zup_app/core/dtos/pool_search_settings_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/mixins/keys_mixin.dart'; import 'package:zup_app/core/pool_service.dart'; @@ -57,7 +57,7 @@ class DepositCubit extends Cubit with KeysMixin, CLPoolConversorsM final Duration _poolSqrtPriceX96CacheExpiration = const Duration(seconds: 30); BigInt? _latestPoolSqrtPriceX96; - YieldDto? yieldPool; + LiquidityPoolDto? yieldPool; late final Stream poolSqrtPriceX96Stream = _poolSqrtPriceX96StreamController.stream; diff --git a/lib/app/create/yields/[id]/deposit/deposit_page.dart b/lib/app/create/yields/[id]/deposit/deposit_page.dart index da047e3..0332f1c 100644 --- a/lib/app/create/yields/[id]/deposit/deposit_page.dart +++ b/lib/app/create/yields/[id]/deposit/deposit_page.dart @@ -16,10 +16,10 @@ import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_conversors_mix import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_liquidity_calculations_mixin.dart'; import 'package:zup_app/core/concentrated_liquidity_utils/cl_sqrt_price_math_mixin.dart'; import 'package:zup_app/core/dtos/deposit_settings_dto.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; import 'package:zup_app/core/extensions/num_extension.dart'; import 'package:zup_app/core/extensions/string_extension.dart'; import 'package:zup_app/core/extensions/widget_extension.dart'; @@ -32,6 +32,7 @@ import 'package:zup_app/core/zup_navigator.dart'; import 'package:zup_app/core/zup_route_params_names.dart'; import 'package:zup_app/gen/assets.gen.dart'; import 'package:zup_app/l10n/gen/app_localizations.dart'; +import 'package:zup_app/widgets/pool_info_modal/pool_info_modal.dart'; import 'package:zup_app/widgets/yield_card.dart'; import 'package:zup_app/widgets/zup_skeletonizer.dart'; import 'package:zup_core/zup_core.dart'; @@ -86,14 +87,15 @@ class _DepositPageState extends State AppNetworks get networkFromUrl => AppNetworks.fromValue(_navigator.getQueryParam(DepositRouteParamsNames().network)!) ?? AppNetworks.mainnet; - YieldTimeFrame get yieldTimeFrameFromUrl => - YieldTimeFrame.fromValue(_navigator.getQueryParam(DepositRouteParamsNames().timeframe)!) ?? YieldTimeFrame.day; + PoolDataTimeframe get yieldTimeFrameFromUrl => + PoolDataTimeframe.fromValue(_navigator.getQueryParam(DepositRouteParamsNames().timeframe)!) ?? + PoolDataTimeframe.day; - TokenDto get baseToken { + SingleChainTokenDto get baseToken { return areTokensReversed ? _cubit.yieldPool!.token1 : _cubit.yieldPool!.token0; } - TokenDto get quoteToken { + SingleChainTokenDto get quoteToken { return areTokensReversed ? _cubit.yieldPool!.token0 : _cubit.yieldPool!.token1; } @@ -108,7 +110,7 @@ class _DepositPageState extends State RangeController minRangeController = RangeController(); RangeController maxRangeController = RangeController(); StreamSubscription? _poolSqrtPriceX96StreamSubscription; - YieldTimeFrame yieldPoolTimeFrame = YieldTimeFrame.day; + PoolDataTimeframe yieldPoolTimeFrame = PoolDataTimeframe.day; late Slippage selectedSlippage = _cubit.depositSettings.slippage; late Duration selectedDeadline = _cubit.depositSettings.deadline; @@ -129,8 +131,8 @@ class _DepositPageState extends State final price = sqrtPriceX96ToPrice( sqrtPriceX96: _cubit.latestPoolSqrtPriceX96!, - poolToken0Decimals: _cubit.yieldPool!.token0NetworkDecimals, - poolToken1Decimals: _cubit.yieldPool!.token1NetworkDecimals, + poolToken0Decimals: _cubit.yieldPool!.token0.decimals, + poolToken1Decimals: _cubit.yieldPool!.token1.decimals, ); return areTokensReversed ? price.token1PerToken0 : price.token0PerToken1; @@ -205,14 +207,14 @@ class _DepositPageState extends State final maxTickPrice = tickToPrice( tick: CLPoolConstants.maxTick, - poolToken0Decimals: _cubit.yieldPool!.token0NetworkDecimals, - poolToken1Decimals: _cubit.yieldPool!.token1NetworkDecimals, + poolToken0Decimals: _cubit.yieldPool!.token0.decimals, + poolToken1Decimals: _cubit.yieldPool!.token1.decimals, ); final minTickPrice = tickToPrice( tick: CLPoolConstants.minTick, - poolToken0Decimals: _cubit.yieldPool!.token0NetworkDecimals, - poolToken1Decimals: _cubit.yieldPool!.token1NetworkDecimals, + poolToken0Decimals: _cubit.yieldPool!.token0.decimals, + poolToken1Decimals: _cubit.yieldPool!.token1.decimals, ); double getMinPrice() { @@ -234,7 +236,7 @@ class _DepositPageState extends State priceUpper: getMaxPrice(), tokenXAmount: double.tryParse(baseTokenAmountController.text) ?? 0, ).toString(), - )?.toStringAsFixed(quoteToken.decimals[_cubit.yieldPool!.network.chainId]!); + )?.toStringAsFixed(quoteToken.decimals); final newBaseTokenAmount = Decimal.tryParse( calculateToken0AmountFromToken1( @@ -243,7 +245,7 @@ class _DepositPageState extends State priceUpper: getMaxPrice(), tokenYAmount: double.tryParse(quoteTokenAmountController.text) ?? 0, ).toString(), - )?.toStringAsFixed(baseToken.decimals[_cubit.yieldPool!.network.chainId]!); + )?.toStringAsFixed(baseToken.decimals); if (isBaseTokenAmountUserInput) { if (newQuoteTokenAmount?.isEmptyOrZero ?? true) return quoteTokenAmountController.clear(); @@ -258,12 +260,12 @@ class _DepositPageState extends State Future<({String title, Widget? icon, Function()? onPressed})> depositButtonState() async { final userWalletBaseTokenAmount = await _cubit.getWalletTokenAmount( - baseToken.addresses[_cubit.yieldPool!.network.chainId]!, + baseToken.address, network: _cubit.yieldPool!.network, ); final userWalletQuoteTokenAmount = await _cubit.getWalletTokenAmount( - quoteToken.addresses[_cubit.yieldPool!.network.chainId]!, + quoteToken.address, network: _cubit.yieldPool!.network, ); @@ -398,7 +400,7 @@ class _DepositPageState extends State ? S .of(context) .depositPagePercentSlippage( - valuePercent: selectedSlippage.value.formatPercent, + valuePercent: selectedSlippage.value.formatRoundingPercent, ) : null, onPressed: (buttonContext) => ZupPopover.show( @@ -494,8 +496,8 @@ class _DepositPageState extends State children: [ ZupSkeletonizer( child: YieldCard( - yieldPool: YieldDto.fixture().copyWith(chainId: networkFromUrl.chainId), - yieldTimeFrame: YieldTimeFrame.day, + yieldPool: LiquidityPoolDto.fixture().copyWith(chainId: networkFromUrl.chainId), + yieldTimeFrame: PoolDataTimeframe.day, showHotestYieldAnimation: false, ), ).animate( @@ -523,19 +525,25 @@ class _DepositPageState extends State ); } - Widget _buildYieldCard(YieldDto yieldPool) => YieldCard( + Widget _buildYieldCard(LiquidityPoolDto yieldPool) => YieldCard( yieldPool: yieldPool, yieldTimeFrame: yieldTimeFrameFromUrl, expandWidth: shouldYieldCardBeInColumn, showHotestYieldAnimation: false, showTimeframe: !_navigator.canBack(context), - mainButton: const ZupPrimaryButton( - title: "Pool Stats (Soon)", + mainButton: ZupPrimaryButton( + title: "Pool Stats", fixedIcon: true, - isTrailingIcon: true, - onPressed: null, - backgroundColor: ZupColors.gray6, + isTrailingIcon: false, + onPressed: (_) => PoolInfoModal.show( + context, + showAsBottomSheet: isMobileSize(context), + liquidityPool: yieldPool, + selectedTimeframe: yieldTimeFrameFromUrl, + ), + backgroundColor: ZupThemeColors.tertiaryButtonBackground.themed(context.brightness), foregroundColor: ZupColors.brand, + icon: Assets.icons.chartBar.svg(height: 13, width: 13), hoverElevation: 0, ), ); @@ -605,7 +613,7 @@ class _DepositPageState extends State builder: (context, poolSqrtPriceX96Snaphot) { return Text( "1 ${baseToken.symbol} ≈ ${() { - final currentPrice = sqrtPriceX96ToPrice(sqrtPriceX96: poolSqrtPriceX96Snaphot.data ?? BigInt.zero, poolToken0Decimals: _cubit.yieldPool!.token0NetworkDecimals, poolToken1Decimals: _cubit.yieldPool!.token1NetworkDecimals); + final currentPrice = sqrtPriceX96ToPrice(sqrtPriceX96: poolSqrtPriceX96Snaphot.data ?? BigInt.zero, poolToken0Decimals: _cubit.yieldPool!.token0.decimals, poolToken1Decimals: _cubit.yieldPool!.token1.decimals); return areTokensReversed ? currentPrice.token1PerToken0 : currentPrice.token0PerToken1; }.call().formatCurrency(useLessThan: true, maxDecimals: 4, isUSD: false)} ${quoteToken.symbol}", @@ -685,8 +693,8 @@ class _DepositPageState extends State }); }, initialPrice: minPrice, - poolToken0Decimals: _cubit.yieldPool!.token0NetworkDecimals, - poolToken1Decimals: _cubit.yieldPool!.token1NetworkDecimals, + poolToken0Decimals: _cubit.yieldPool!.token0.decimals, + poolToken1Decimals: _cubit.yieldPool!.token1.decimals, isReversed: areTokensReversed, displayBaseTokenSymbol: baseToken.symbol, displayQuoteTokenSymbol: quoteToken.symbol, @@ -733,8 +741,8 @@ class _DepositPageState extends State type: RangeSelectorType.maxPrice, isInfinity: isMaxRangeInfinity, initialPrice: maxPrice, - poolToken0Decimals: _cubit.yieldPool!.token0NetworkDecimals, - poolToken1Decimals: _cubit.yieldPool!.token1NetworkDecimals, + poolToken0Decimals: _cubit.yieldPool!.token0.decimals, + poolToken1Decimals: _cubit.yieldPool!.token1.decimals, isReversed: areTokensReversed, tickSpacing: _cubit.yieldPool!.tickSpacing, rangeController: maxRangeController, @@ -780,9 +788,7 @@ class _DepositPageState extends State TokenAmountInputCard( key: const Key("base-token-input-card"), token: baseToken, - isNative: baseToken.addresses[_cubit.yieldPool!.network.chainId]!.lowercasedEquals( - EthereumConstants.zeroAddress, - ), + isNative: baseToken.address.lowercasedEquals(EthereumConstants.zeroAddress), onRefreshBalance: () => setState(() {}), disabledText: () { if (!isBaseTokenNeeded) { @@ -809,9 +815,7 @@ class _DepositPageState extends State TokenAmountInputCard( key: const Key("quote-token-input-card"), token: quoteToken, - isNative: quoteToken.addresses[_cubit.yieldPool!.network.chainId]!.lowercasedEquals( - EthereumConstants.zeroAddress, - ), + isNative: quoteToken.address.lowercasedEquals(EthereumConstants.zeroAddress), onRefreshBalance: () => setState(() {}), disabledText: () { if (!isQuoteTokenNeeded) { diff --git a/lib/app/create/yields/[id]/deposit/deposit_state.dart b/lib/app/create/yields/[id]/deposit/deposit_state.dart index 6accdbd..792d102 100644 --- a/lib/app/create/yields/[id]/deposit/deposit_state.dart +++ b/lib/app/create/yields/[id]/deposit/deposit_state.dart @@ -4,6 +4,6 @@ part of 'deposit_cubit.dart'; class DepositState with _$DepositState { const factory DepositState.initial() = _Initial; const factory DepositState.loading() = _Loading; - const factory DepositState.success(YieldDto yieldPool) = _Success; + const factory DepositState.success(LiquidityPoolDto yieldPool) = _Success; const factory DepositState.error() = _Error; } diff --git a/lib/app/create/yields/[id]/deposit/widgets/deposit_success_modal.dart b/lib/app/create/yields/[id]/deposit/widgets/deposit_success_modal.dart index bccb52f..7fc1244 100644 --- a/lib/app/create/yields/[id]/deposit/widgets/deposit_success_modal.dart +++ b/lib/app/create/yields/[id]/deposit/widgets/deposit_success_modal.dart @@ -1,23 +1,21 @@ import 'package:confetti/confetti.dart'; import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/gen/assets.gen.dart'; import 'package:zup_app/l10n/gen/app_localizations.dart'; -import 'package:zup_app/widgets/token_avatar.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; import 'package:zup_core/zup_core.dart'; import 'package:zup_ui_kit/zup_ui_kit.dart'; class DepositSuccessModal extends StatefulWidget { const DepositSuccessModal({super.key, required this.depositedYield}); - final YieldDto depositedYield; + final LiquidityPoolDto depositedYield; static Future show( BuildContext context, { - required YieldDto depositedYield, + required LiquidityPoolDto depositedYield, required showAsBottomSheet, }) async => ZupModal.show( context, @@ -33,7 +31,7 @@ class DepositSuccessModal extends StatefulWidget { } class _DepositSuccessModalState extends State { - final zupCachedImage = inject(); + final zupNetworkImage = inject(); final confettiController = inject(instanceName: InjectInstanceNames.confettiController10s); @override @@ -58,8 +56,18 @@ class _DepositSuccessModalState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ ZupMergedWidgets( - firstWidget: TokenAvatar(asset: widget.depositedYield.token0, size: 70), - secondWidget: TokenAvatar(asset: widget.depositedYield.token1, size: 70), + firstWidget: ZupRemoteAvatar( + zupNetworkImage: zupNetworkImage, + avatarUrl: widget.depositedYield.token0.logoUrl, + errorPlaceholder: widget.depositedYield.token0.name[0], + size: 70, + ), + secondWidget: ZupRemoteAvatar( + zupNetworkImage: zupNetworkImage, + avatarUrl: widget.depositedYield.token1.logoUrl, + errorPlaceholder: widget.depositedYield.token1.name[0], + size: 70, + ), spacing: 0, ), const SizedBox(width: 20), @@ -79,7 +87,7 @@ class _DepositSuccessModalState extends State { particleDrag: 0.03, ), const SizedBox(width: 20), - zupCachedImage.build(context, widget.depositedYield.protocol.logo, radius: 50, height: 70, width: 70), + zupNetworkImage.load(context, widget.depositedYield.protocol.logo, radius: 50, height: 70, width: 70), ], ), const SizedBox(height: 30), diff --git a/lib/app/create/yields/[id]/deposit/widgets/preview_deposit_modal/preview_deposit_modal.dart b/lib/app/create/yields/[id]/deposit/widgets/preview_deposit_modal/preview_deposit_modal.dart index cbf576e..c9fb67c 100644 --- a/lib/app/create/yields/[id]/deposit/widgets/preview_deposit_modal/preview_deposit_modal.dart +++ b/lib/app/create/yields/[id]/deposit/widgets/preview_deposit_modal/preview_deposit_modal.dart @@ -12,9 +12,9 @@ import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/widgets/preview_depos import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_constants.dart'; import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_conversors_mixin.dart'; import 'package:zup_app/core/concentrated_liquidity_utils/cl_sqrt_price_math_mixin.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; import 'package:zup_app/core/extensions/num_extension.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/core/pool_service.dart'; @@ -24,8 +24,6 @@ import 'package:zup_app/core/zup_links.dart'; import 'package:zup_app/core/zup_navigator.dart'; import 'package:zup_app/gen/assets.gen.dart'; import 'package:zup_app/l10n/gen/app_localizations.dart'; -import 'package:zup_app/widgets/token_avatar.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; import 'package:zup_core/extensions/text_edititing_controller_extension.dart'; import 'package:zup_core/zup_core.dart'; import 'package:zup_ui_kit/zup_ui_kit.dart'; @@ -44,8 +42,8 @@ class PreviewDepositModal extends StatefulWidget with DeviceInfoMixin { required this.yieldTimeFrame, }); - final YieldDto currentYield; - final YieldTimeFrame yieldTimeFrame; + final LiquidityPoolDto currentYield; + final PoolDataTimeframe yieldTimeFrame; final bool isReversed; final ({double price, bool isInfinity}) minPrice; final ({double price, bool isInfinity}) maxPrice; @@ -96,7 +94,7 @@ class PreviewDepositModal extends StatefulWidget with DeviceInfoMixin { class _PreviewDepositModalState extends State with CLPoolConversorsMixin, CLSqrtPriceMath, DeviceInfoMixin { - final zupCachedImage = inject(); + final zupNetworkImage = inject(); final navigator = inject(); final zupLinks = inject(); @@ -108,7 +106,7 @@ class _PreviewDepositModalState extends State WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {})); }; - TokenDto get baseToken { + SingleChainTokenDto get baseToken { if (isReversedLocal) { return widget.currentYield.token1; } @@ -116,7 +114,7 @@ class _PreviewDepositModalState extends State return widget.currentYield.token0; } - TokenDto get quoteToken { + SingleChainTokenDto get quoteToken { if (isReversedLocal) { return widget.currentYield.token0; } @@ -135,18 +133,18 @@ class _PreviewDepositModalState extends State : widget.token1DepositAmountController.parseTextToDoubleOrZero; BigInt get token0DepositAmount => widget.token0DepositAmountController.parseTextToDoubleOrZero.parseTokenAmount( - decimals: widget.currentYield.token0NetworkDecimals, + decimals: widget.currentYield.token0.decimals, ); BigInt get token1DepositAmount => widget.token1DepositAmountController.parseTextToDoubleOrZero.parseTokenAmount( - decimals: widget.currentYield.token1NetworkDecimals, + decimals: widget.currentYield.token1.decimals, ); double get currentPrice { final price = sqrtPriceX96ToPrice( sqrtPriceX96: cubit.latestPriceX96, - poolToken0Decimals: widget.currentYield.token0NetworkDecimals, - poolToken1Decimals: widget.currentYield.token1NetworkDecimals, + poolToken0Decimals: widget.currentYield.token0.decimals, + poolToken1Decimals: widget.currentYield.token1.decimals, ); return isReversedLocal ? price.token1PerToken0 : price.token0PerToken1; @@ -158,16 +156,16 @@ class _PreviewDepositModalState extends State return priceToTick( price: (widget.isReversed == !isReversedLocal) ? widget.maxPrice.price : widget.minPrice.price, - poolToken0Decimals: widget.currentYield.token0NetworkDecimals, - poolToken1Decimals: widget.currentYield.token1NetworkDecimals, + poolToken0Decimals: widget.currentYield.token0.decimals, + poolToken1Decimals: widget.currentYield.token1.decimals, isReversed: widget.isReversed, ); } ({double priceAsBaseToken, double priceAsQuoteToken}) price() => tickToPrice( tick: tick(), - poolToken0Decimals: widget.currentYield.token0NetworkDecimals, - poolToken1Decimals: widget.currentYield.token1NetworkDecimals, + poolToken0Decimals: widget.currentYield.token0.decimals, + poolToken1Decimals: widget.currentYield.token1.decimals, ); return isReversedLocal ? price().priceAsQuoteToken : price().priceAsBaseToken; @@ -179,16 +177,16 @@ class _PreviewDepositModalState extends State return priceToTick( price: (widget.isReversed == !isReversedLocal) ? widget.minPrice.price : widget.maxPrice.price, - poolToken0Decimals: widget.currentYield.token0NetworkDecimals, - poolToken1Decimals: widget.currentYield.token1NetworkDecimals, + poolToken0Decimals: widget.currentYield.token0.decimals, + poolToken1Decimals: widget.currentYield.token1.decimals, isReversed: widget.isReversed, ); } ({double priceAsBaseToken, double priceAsQuoteToken}) price() => tickToPrice( tick: tick(), - poolToken0Decimals: widget.currentYield.token0NetworkDecimals, - poolToken1Decimals: widget.currentYield.token1NetworkDecimals, + poolToken0Decimals: widget.currentYield.token0.decimals, + poolToken1Decimals: widget.currentYield.token1.decimals, ); return isReversedLocal ? price().priceAsQuoteToken : price().priceAsBaseToken; @@ -405,8 +403,17 @@ class _PreviewDepositModalState extends State children: [ ZupMergedWidgets( spacing: 0, - firstWidget: TokenAvatar(asset: baseToken, size: 35), - secondWidget: TokenAvatar(asset: quoteToken, size: 35), + firstWidget: ZupRemoteAvatar( + zupNetworkImage: zupNetworkImage, + avatarUrl: baseToken.logoUrl, + errorPlaceholder: baseToken.name[0], + size: 35, + ), + secondWidget: ZupRemoteAvatar( + avatarUrl: quoteToken.logoUrl, + errorPlaceholder: quoteToken.name[0], + size: 35, + ), ), const SizedBox(width: 5), Text( @@ -417,7 +424,7 @@ class _PreviewDepositModalState extends State StreamBuilder( stream: cubit.poolSqrtPriceX96Stream, builder: (context, _) { - return ZupTag( + return ZupOutlinedTag( title: isOutOfRange.any ? S.of(context).previewDepositModalOutOfRange : S.of(context).previewDepositModalInRange, @@ -468,7 +475,7 @@ class _PreviewDepositModalState extends State const SizedBox(height: 10), Row( children: [ - zupCachedImage.build( + zupNetworkImage.load( context, baseToken.logoUrl, height: 30, @@ -496,7 +503,7 @@ class _PreviewDepositModalState extends State const SizedBox(height: 15), Row( children: [ - zupCachedImage.build( + zupNetworkImage.load( context, quoteToken.logoUrl, height: 30, @@ -532,7 +539,7 @@ class _PreviewDepositModalState extends State fit: FlexFit.loose, child: _fieldColumn( title: S.of(context).previewDepositModalProtocol, - image: zupCachedImage.build( + image: zupNetworkImage.load( context, widget.currentYield.protocol.logo, width: 30, @@ -572,7 +579,7 @@ class _PreviewDepositModalState extends State spacing: 0, title: "${S.of(context).previewDepositModalYearlyYield} (${widget.yieldTimeFrame.label(context)})", - value: widget.currentYield.yieldTimeframed(widget.yieldTimeFrame).formatPercent, + value: widget.currentYield.yieldTimeframed(widget.yieldTimeFrame).formatRoundingPercent, ), const SizedBox(height: 10), const ZupDivider(), diff --git a/lib/app/create/yields/[id]/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit.dart b/lib/app/create/yields/[id]/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit.dart index 8687653..5d8c7ba 100644 --- a/lib/app/create/yields/[id]/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit.dart +++ b/lib/app/create/yields/[id]/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit.dart @@ -12,8 +12,8 @@ import 'package:zup_app/abis/uniswap_v3_position_manager.abi.g.dart'; import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/widgets/deposit_success_modal.dart'; import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_constants.dart'; import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_conversors_mixin.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; import 'package:zup_app/core/pool_service.dart'; import 'package:zup_app/core/slippage.dart'; import 'package:zup_app/core/zup_analytics.dart'; @@ -28,7 +28,7 @@ class PreviewDepositModalCubit extends Cubit with CLPo PreviewDepositModalCubit({ required BigInt currentPriceX96, required PoolService poolService, - required YieldDto currentYield, + required LiquidityPoolDto currentYield, required Erc20 erc20, required Wallet wallet, required UniswapV3PositionManager uniswapPositionManager, @@ -47,7 +47,7 @@ class PreviewDepositModalCubit extends Cubit with CLPo final PoolService _poolRepository; final Erc20 _erc20; - final YieldDto _yield; + final LiquidityPoolDto _yield; final Wallet _wallet; final GlobalKey _navigatorKey; @@ -79,10 +79,10 @@ class PreviewDepositModalCubit extends Cubit with CLPo emit(PreviewDepositModalState.initial(token0Allowance: _token0Allowance, token1Allowance: _token1Allowance)); } - Future approveToken(TokenDto token, BigInt value) async { + Future approveToken(SingleChainTokenDto token, BigInt value) async { try { final spender = _yield.poolType.isV4 ? _yield.permit2! : _yield.positionManagerAddress; - final tokenAddressInNetwork = token.addresses[_yield.network.chainId]!; + final tokenAddressInNetwork = token.address; emit(PreviewDepositModalState.approvingToken(token.symbol)); await _maybeSwitchNetwork(); @@ -100,8 +100,8 @@ class PreviewDepositModalCubit extends Cubit with CLPo try { await _getTokensAllowance(canThrow: true); } catch (e) { - if (_yield.token0.addresses[_yield.network.chainId] == tokenAddressInNetwork) _token0Allowance = value; - if (_yield.token1.addresses[_yield.network.chainId] == tokenAddressInNetwork) _token1Allowance = value; + if (_yield.token0.address == tokenAddressInNetwork) _token0Allowance = value; + if (_yield.token1.address == tokenAddressInNetwork) _token1Allowance = value; } emit(PreviewDepositModalState.approveSuccess(txId: tx.hash, symbol: token.symbol)); @@ -118,23 +118,21 @@ class PreviewDepositModalCubit extends Cubit with CLPo } } - Future checkOrApprovePermit2ForV4Pool(BigInt approveValue, TokenDto token) async { - final tokenAddressInNetwork = token.addresses[_yield.network.chainId]!; - - if (tokenAddressInNetwork == EthereumConstants.zeroAddress) return; + Future checkOrApprovePermit2ForV4Pool(BigInt approveValue, SingleChainTokenDto token) async { + if (token.address == EthereumConstants.zeroAddress) return; final permit2Contract = _permit2.fromSigner(contractAddress: _yield.permit2!, signer: _wallet.signer!); final permit2CurrentAllowance = await permit2Contract.allowance( await _wallet.signer!.address, - tokenAddressInNetwork, + token.address, _yield.positionManagerAddress, ); if (permit2CurrentAllowance.amount <= approveValue || permit2CurrentAllowance.expiration < BigInt.from(DateTime.now().millisecondsSinceEpoch / 1000)) { final tx = await permit2Contract.approve( - token: tokenAddressInNetwork, + token: token.address, spender: _yield.positionManagerAddress, amount: EthereumConstants.uint160Max, expiration: EthereumConstants.uint48Max, @@ -166,8 +164,8 @@ class PreviewDepositModalCubit extends Cubit with CLPo return priceToTick( price: isReversed ? maxPrice : minPrice, - poolToken0Decimals: _yield.token0NetworkDecimals, - poolToken1Decimals: _yield.token1NetworkDecimals, + poolToken0Decimals: _yield.token0.decimals, + poolToken1Decimals: _yield.token1.decimals, isReversed: isReversed, ); } @@ -182,8 +180,8 @@ class PreviewDepositModalCubit extends Cubit with CLPo return priceToTick( price: isReversed ? minPrice : maxPrice, - poolToken0Decimals: _yield.token0NetworkDecimals, - poolToken1Decimals: _yield.token1NetworkDecimals, + poolToken0Decimals: _yield.token0.decimals, + poolToken1Decimals: _yield.token1.decimals, isReversed: isReversed, ); } @@ -233,8 +231,8 @@ class PreviewDepositModalCubit extends Cubit with CLPo emit(PreviewDepositModalState.depositSuccess(txId: tx.hash)); _zupAnalytics.logDeposit( depositedYield: _yield, - amount0Formatted: amount0Desired.parseTokenAmount(decimals: _yield.token0NetworkDecimals), - amount1Formatted: amount1Desired.parseTokenAmount(decimals: _yield.token1NetworkDecimals), + amount0Formatted: amount0Desired.parseTokenAmount(decimals: _yield.token0.decimals), + amount1Formatted: amount1Desired.parseTokenAmount(decimals: _yield.token1.decimals), walletAddress: recipient, ); } catch (e) { @@ -273,7 +271,7 @@ class PreviewDepositModalCubit extends Cubit with CLPo if (!_yield.isToken0Native) { final token0contract = _erc20.fromRpcProvider( - contractAddress: _yield.token0.addresses[_yield.network.chainId]!, + contractAddress: _yield.token0.address, rpcUrl: _yield.network.rpcUrl, ); @@ -282,7 +280,7 @@ class PreviewDepositModalCubit extends Cubit with CLPo if (!_yield.isToken1Native) { final token1contract = _erc20.fromRpcProvider( - contractAddress: _yield.token1.addresses[_yield.network.chainId]!, + contractAddress: _yield.token1.address, rpcUrl: _yield.network.rpcUrl, ); diff --git a/lib/app/create/yields/[id]/deposit/widgets/range_selector.dart b/lib/app/create/yields/[id]/deposit/widgets/range_selector.dart index c6c8b69..19d8143 100644 --- a/lib/app/create/yields/[id]/deposit/widgets/range_selector.dart +++ b/lib/app/create/yields/[id]/deposit/widgets/range_selector.dart @@ -362,11 +362,15 @@ class _RangeSelectorState extends State with CLPoolConversorsMixi const SizedBox(width: 8), ZupIconButton( key: const Key("increase-button"), - icon: Assets.icons.plus.svg(), + icon: Assets.icons.plus.svg( + colorFilter: ColorFilter.mode( + widget.state.type.adjustmentIconForegroundColor(context), + BlendMode.srcIn, + ), + ), circle: false, minimumHeight: 40, padding: const EdgeInsets.all(12), - iconColor: widget.state.type.adjustmentIconForegroundColor(context), backgroundColor: widget.state.type.adjustmentIconBackgroundColor(context), onPressed: (_) => increaseOrDecrease(increasing: true), ), @@ -376,9 +380,13 @@ class _RangeSelectorState extends State with CLPoolConversorsMixi circle: false, padding: const EdgeInsets.all(12), minimumHeight: 40, - icon: Assets.icons.minus.svg(), + icon: Assets.icons.minus.svg( + colorFilter: ColorFilter.mode( + widget.state.type.adjustmentIconForegroundColor(context), + BlendMode.srcIn, + ), + ), backgroundColor: widget.state.type.adjustmentIconBackgroundColor(context), - iconColor: widget.state.type.adjustmentIconForegroundColor(context), onPressed: (_) => increaseOrDecrease(increasing: false), ), ], diff --git a/lib/app/create/yields/[id]/deposit/widgets/token_amount_input_card/token_amount_input_card.dart b/lib/app/create/yields/[id]/deposit/widgets/token_amount_input_card/token_amount_input_card.dart index 140c133..a96edda 100644 --- a/lib/app/create/yields/[id]/deposit/widgets/token_amount_input_card/token_amount_input_card.dart +++ b/lib/app/create/yields/[id]/deposit/widgets/token_amount_input_card/token_amount_input_card.dart @@ -3,7 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:web3kit/web3kit.dart'; import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/widgets/token_amount_input_card/token_amount_input_card_cubit.dart'; import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/widgets/token_amount_input_card/token_amount_input_card_user_balance_cubit.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/extensions/num_extension.dart'; import 'package:zup_app/core/extensions/widget_extension.dart'; @@ -11,7 +11,7 @@ import 'package:zup_app/core/injections.dart'; import 'package:zup_app/core/repositories/tokens_repository.dart'; import 'package:zup_app/core/token_amount_input_formatter.dart'; import 'package:zup_app/gen/assets.gen.dart'; -import 'package:zup_app/widgets/position_token.dart'; +import 'package:zup_app/widgets/pool_token.dart'; import 'package:zup_core/zup_core.dart'; import 'package:zup_ui_kit/zup_ui_kit.dart'; @@ -27,7 +27,7 @@ class TokenAmountInputCard extends StatefulWidget { this.isNative = false, }); - final TokenDto token; + final SingleChainTokenDto token; final AppNetworks network; final TextEditingController controller; final Function(double value) onInput; @@ -51,7 +51,7 @@ class _TokenAmountInputCardState extends State with Single late TokenAmountCardUserBalanceCubit userBalanceCubit = TokenAmountCardUserBalanceCubit( wallet, - widget.token.addresses[widget.network.chainId]!, + widget.token.address, widget.network, zupSingletonCache, widget.onRefreshBalance, @@ -74,7 +74,7 @@ class _TokenAmountInputCardState extends State with Single @override void didUpdateWidget(TokenAmountInputCard oldWidget) { if ((widget.isNative != oldWidget.isNative || widget.network != oldWidget.network) && - (widget.token.addresses[widget.network.chainId] ?? "").lowercasedEquals(EthereumConstants.zeroAddress)) { + (widget.token.address).lowercasedEquals(EthereumConstants.zeroAddress)) { WidgetsBinding.instance.addPostFrameCallback( (_) => userBalanceCubit.updateNativeTokenAndFetch(isNative: widget.isNative, network: widget.network), ); @@ -84,11 +84,7 @@ class _TokenAmountInputCardState extends State with Single if (widget.token != oldWidget.token || widget.network != oldWidget.network) { WidgetsBinding.instance.addPostFrameCallback((_) { - userBalanceCubit.updateTokenAndNetwork( - widget.token.addresses[widget.network.chainId]!, - widget.network, - asNativeToken: widget.isNative, - ); + userBalanceCubit.updateTokenAndNetwork(widget.token.address, widget.network, asNativeToken: widget.isNative); }); super.didUpdateWidget(oldWidget); @@ -214,7 +210,7 @@ class _TokenAmountInputCardState extends State with Single color: ZupThemeColors.borderOnBackgroundSurface.themed(context.brightness), ), ), - child: PositionToken(token: widget.token), + child: PoolToken(token: widget.token), ), ], ), diff --git a/lib/app/create/yields/[id]/deposit/widgets/token_amount_input_card/token_amount_input_card_cubit.dart b/lib/app/create/yields/[id]/deposit/widgets/token_amount_input_card/token_amount_input_card_cubit.dart index d97b867..e17e945 100644 --- a/lib/app/create/yields/[id]/deposit/widgets/token_amount_input_card/token_amount_input_card_cubit.dart +++ b/lib/app/create/yields/[id]/deposit/widgets/token_amount_input_card/token_amount_input_card_cubit.dart @@ -1,6 +1,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/mixins/keys_mixin.dart'; import 'package:zup_app/core/repositories/tokens_repository.dart'; @@ -11,21 +11,21 @@ part 'token_amount_input_card_state.dart'; class TokenAmountInputCardCubit extends Cubit with KeysMixin { TokenAmountInputCardCubit(this._tokensRepository, this._zupSingletonCache, this._zupHolder) - : super(const TokenAmountInputCardState.initial()); + : super(const TokenAmountInputCardState.initial()); final TokensRepository _tokensRepository; final ZupSingletonCache _zupSingletonCache; final ZupHolder _zupHolder; - Future getTokenPrice({required TokenDto token, required AppNetworks network}) async { + Future getTokenPrice({required SingleChainTokenDto token, required AppNetworks network}) async { try { - final tokenAddress = token.addresses[network.chainId]!; - - return await _zupHolder.hold(() async => await _zupSingletonCache.run( - () async => (await _tokensRepository.getTokenPrice(tokenAddress, network)).usdPrice, - expiration: const Duration(minutes: 1), - key: tokenPriceCacheKey(tokenAddress: tokenAddress, network: network), - )); + return await _zupHolder.hold( + () async => await _zupSingletonCache.run( + () async => (await _tokensRepository.getTokenPrice(token.address, network)).usdPrice, + expiration: const Duration(minutes: 1), + key: tokenPriceCacheKey(tokenAddress: token.address, network: network), + ), + ); } catch (_) { return 0; } diff --git a/lib/app/create/yields/[id]/deposit/widgets/yield_card_temp.dart b/lib/app/create/yields/[id]/deposit/widgets/yield_card_temp.dart deleted file mode 100644 index 8128ca6..0000000 --- a/lib/app/create/yields/[id]/deposit/widgets/yield_card_temp.dart +++ /dev/null @@ -1,207 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_animate/flutter_animate.dart'; -import 'package:intl/intl.dart'; -import 'package:url_launcher/url_launcher.dart'; -import 'package:zup_app/app/app_cubit/app_cubit.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; -import 'package:zup_app/core/extensions/num_extension.dart'; -import 'package:zup_app/core/injections.dart'; -import 'package:zup_app/l10n/gen/app_localizations.dart'; -import 'package:zup_app/widgets/token_avatar.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; -import 'package:zup_core/extensions/extensions.dart'; -import 'package:zup_ui_kit/zup_ui_kit.dart'; - -class YieldCardTemp extends StatefulWidget { - const YieldCardTemp({ - super.key, - required this.currentYield, - required this.onChangeSelection, - required this.isSelected, - required this.timeFrame, - this.isHotestYield = false, - }); - - final YieldDto currentYield; - final bool isSelected; - final Function(YieldDto? yield) onChangeSelection; - final YieldTimeFrame timeFrame; - final bool isHotestYield; - - @override - State createState() => _YieldCardTempState(); -} - -class _YieldCardTempState extends State { - final zupCachedImage = inject(); - final appCubit = inject(); - final infinityAnimationAutoPlay = inject(instanceName: InjectInstanceNames.infinityAnimationAutoPlay); - - final selectionAnimationDuration = const Duration(milliseconds: 150); - - Widget get yieldText => Text( - widget.currentYield.yieldTimeframed(widget.timeFrame).formatPercent, - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.w600, - color: ZupThemeColors.backgroundInverse.themed(context.brightness), - ), - ); - - @override - Widget build(BuildContext context) { - return ZupSelectableCard( - isSelected: widget.isSelected, - selectionAnimationDuration: selectionAnimationDuration, - - onPressed: () { - return widget.onChangeSelection(widget.isSelected ? null : widget.currentYield); - }, - padding: const EdgeInsets.all(10).copyWith(right: 2, top: 2, bottom: 0), - child: Stack( - children: [ - if (appCubit.selectedNetwork.isAllNetworks) - Positioned( - right: 2, - top: 2, - child: ZupTooltip.text( - message: S.of(context).yieldCardThisPoolIsAtNetwork(network: widget.currentYield.network.label), - trailingIcon: widget.currentYield.network.icon(context.brightness), - child: Container( - height: 40, - padding: const EdgeInsets.all(6), - width: 40, - decoration: BoxDecoration( - color: widget.isSelected - ? ZupColors.brand.withValues(alpha: 0.1) - : (context.brightness.isDark ? ZupColors.black2 : ZupColors.gray6), - borderRadius: BorderRadius.circular(8), - ), - child: widget.currentYield.network.icon(context.brightness), - ), - ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(top: 10), - child: Text( - widget.timeFrame.isDay - ? S.of(context).yieldCardYearlyYield - : S.of(context).yieldCardAverageYieldYearly, - style: TextStyle(fontSize: 14, color: ZupThemeColors.primaryText.themed(context.brightness)), - ), - ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (widget.isHotestYield) ...[ - yieldText.animate( - effects: [ - const ScaleEffect( - duration: Duration(milliseconds: 200), - alignment: Alignment.center, - begin: Offset(1.1, 1.1), - end: Offset(1, 1), - ), - ShimmerEffect( - duration: const Duration(seconds: 2), - color: ZupThemeColors.shimmer.themed(context.brightness), - curve: Curves.decelerate, - angle: 90, - size: 1, - ), - ], - autoPlay: infinityAnimationAutoPlay, - onComplete: (controller) => controller.repeat(reverse: true), - ), - ] else - yieldText, - ], - ), - Text( - "${NumberFormat.compactSimpleCurrency(decimalDigits: 2).format(widget.currentYield.totalValueLockedUSD)} ${S.of(context).tvl}", - style: const TextStyle(fontSize: 14, height: 1, color: ZupColors.gray), - ), - const SizedBox(height: 10), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - padding: const EdgeInsets.all(6), - decoration: BoxDecoration( - color: widget.isSelected - ? (context.brightness.isDark ? ZupColors.brand.withValues(alpha: 0.1) : ZupColors.brand5) - : (context.brightness.isDark ? ZupColors.black2 : ZupColors.gray6), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - ZupMergedWidgets( - firstWidget: TokenAvatar(asset: widget.currentYield.token0, size: 25), - secondWidget: TokenAvatar(asset: widget.currentYield.token1, size: 25), - spacing: 0, - ), - const SizedBox(width: 10), - Text( - "${widget.currentYield.token0.symbol}/${widget.currentYield.token1.symbol}", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: ZupThemeColors.primaryText.themed(context.brightness), - ), - ), - ], - ), - ), - const SizedBox(width: 10), - const Text(">", style: TextStyle(color: ZupColors.gray)), - const SizedBox(width: 10), - if (widget.currentYield.protocol.logo.isNotEmpty) - zupCachedImage.build( - context, - widget.currentYield.protocol.logo, - height: 25, - width: 25, - radius: 50, - errorWidget: (context, error, stackTrace) { - return Container( - height: 25, - width: 25, - decoration: BoxDecoration(color: ZupColors.gray6, borderRadius: BorderRadius.circular(50)), - ); - }, - ), - const SizedBox(width: 5), - Flexible( - child: ZupTooltip.text( - message: "", - helperButtonTitle: S - .of(context) - .yieldCardVisitProtocol(protocolName: widget.currentYield.protocol.name), - helperButtonOnPressed: () => launchUrl(Uri.parse(widget.currentYield.protocol.url)), - child: Text( - widget.currentYield.protocol.name, - overflow: TextOverflow.ellipsis, - maxLines: 1, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: ZupThemeColors.backgroundInverse.themed(context.brightness), - ), - ), - ), - ), - const SizedBox(width: 20), - ], - ), - ], - ), - ], - ), - ); - } -} diff --git a/lib/app/create/yields/yields_cubit.dart b/lib/app/create/yields/yields_cubit.dart index 9fcea02..0f48148 100644 --- a/lib/app/create/yields/yields_cubit.dart +++ b/lib/app/create/yields/yields_cubit.dart @@ -2,8 +2,8 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:zup_app/app/app_cubit/app_cubit.dart'; import 'package:zup_app/core/cache.dart'; +import 'package:zup_app/core/dtos/liquidity_pools_search_result_dto.dart'; import 'package:zup_app/core/dtos/pool_search_filters_dto.dart'; -import 'package:zup_app/core/dtos/yields_dto.dart'; import 'package:zup_app/core/repositories/yield_repository.dart'; import 'package:zup_app/core/zup_analytics.dart'; diff --git a/lib/app/create/yields/yields_page.dart b/lib/app/create/yields/yields_page.dart index a7b6f5f..f315b08 100644 --- a/lib/app/create/yields/yields_page.dart +++ b/lib/app/create/yields/yields_page.dart @@ -6,10 +6,10 @@ import 'package:skeletonizer/skeletonizer.dart'; import 'package:zup_app/app/app_cubit/app_cubit.dart'; import 'package:zup_app/app/create/yields/yields_cubit.dart'; import 'package:zup_app/core/cache.dart'; +import 'package:zup_app/core/dtos/liquidity_pools_search_result_dto.dart'; import 'package:zup_app/core/dtos/pool_search_filters_dto.dart'; -import 'package:zup_app/core/dtos/yields_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; import 'package:zup_app/core/enums/zup_navigator_paths.dart'; import 'package:zup_app/core/extensions/num_extension.dart'; import 'package:zup_app/core/injections.dart'; @@ -20,6 +20,7 @@ import 'package:zup_app/core/zup_navigator.dart'; import 'package:zup_app/core/zup_route_params_names.dart'; import 'package:zup_app/gen/assets.gen.dart'; import 'package:zup_app/l10n/gen/app_localizations.dart'; +import 'package:zup_app/widgets/pool_info_modal/pool_info_modal.dart'; import 'package:zup_app/widgets/timeframe_selector.dart'; import 'package:zup_app/widgets/yield_card.dart'; import 'package:zup_app/widgets/zup_page_title.dart'; @@ -84,7 +85,7 @@ class _YieldsPageState extends State with DeviceInfoMixin, SingleTic return navigator.getQueryParam(ZupNavigatorPaths.yields.routeParamsNames().group1); } - YieldTimeFrame selectedYieldTimeFrame = YieldTimeFrame.day; + PoolDataTimeframe selectedYieldTimeFrame = PoolDataTimeframe.day; num currentYieldPage = 0; bool isYieldsPageGoingBackwards = false; @@ -145,7 +146,7 @@ class _YieldsPageState extends State with DeviceInfoMixin, SingleTic ); } - Widget _buildSuccessState(YieldsDto yields) { + Widget _buildSuccessState(LiquidityPoolsSearchResultDto yields) { int getYieldDisplayCountPerPage() { return yields.pools.length.clamp(1, isMobileSize(context) ? 1 : 2); } @@ -171,7 +172,11 @@ class _YieldsPageState extends State with DeviceInfoMixin, SingleTic child: Padding( padding: const EdgeInsets.all(20), child: ZupIconButton( - icon: Assets.icons.arrowLeft.svg(height: 12, width: 12), + icon: Assets.icons.arrowLeft.svg( + height: 12, + width: 12, + colorFilter: const ColorFilter.mode(ZupColors.gray, BlendMode.srcIn), + ), onPressed: (context) async { if (currentYieldPage.equals(0)) return; isYieldsPageGoingBackwards = true; @@ -209,18 +214,20 @@ class _YieldsPageState extends State with DeviceInfoMixin, SingleTic ), const SizedBox(height: 10), TimeframeSelector( + title: S.of(context).yieldsPageTimeframeSelectorTitle, + tooltipMessage: S.of(context).yieldsPageTimeframeExplanation, selectedTimeframe: selectedYieldTimeFrame, onTimeframeSelected: (timeframe) { setState(() { pageController.jumpTo(0); - selectedYieldTimeFrame = timeframe ?? YieldTimeFrame.day; + selectedYieldTimeFrame = timeframe; }); }, ), ], ), ), - const SizedBox(height: 20), + const SizedBox(height: 10), _buildYieldsSection( yieldsPagesCount: yieldsPagesCount, yieldsCardPerPage: getYieldDisplayCountPerPage(), @@ -244,7 +251,11 @@ class _YieldsPageState extends State with DeviceInfoMixin, SingleTic child: Padding( padding: const EdgeInsets.all(20), child: ZupIconButton( - icon: Assets.icons.arrowRight.svg(height: 12, width: 12), + icon: Assets.icons.arrowRight.svg( + height: 12, + width: 12, + colorFilter: const ColorFilter.mode(ZupColors.gray, BlendMode.srcIn), + ), onPressed: (context) { if (currentYieldPage.equals(yieldsPagesCount - 1)) return; isYieldsPageGoingBackwards = false; @@ -267,7 +278,7 @@ class _YieldsPageState extends State with DeviceInfoMixin, SingleTic Widget _buildYieldsSection({ required int yieldsPagesCount, required int yieldsCardPerPage, - required YieldsDto yields, + required LiquidityPoolsSearchResultDto yields, }) { final poolsSortedByTimeframe = yields.poolsSortedByTimeframe(selectedYieldTimeFrame); @@ -309,6 +320,22 @@ class _YieldsPageState extends State with DeviceInfoMixin, SingleTic yieldTimeFrame: selectedYieldTimeFrame, showHotestYieldAnimation: yieldItem.equals(poolsSortedByTimeframe.first), expandWidth: isMobileSize(context), + secondaryButton: ZupIconButton( + key: Key("pool-stats-button-${yieldItem.poolAddress}"), + icon: Assets.icons.chartBar.svg( + height: 15, + width: 15, + colorFilter: const ColorFilter.mode(ZupColors.brand4, BlendMode.srcIn), + ), + onPressed: (_) => PoolInfoModal.show( + context, + showAsBottomSheet: isMobileSize(context), + liquidityPool: yieldItem, + selectedTimeframe: selectedYieldTimeFrame, + ), + backgroundColor: ZupThemeColors.tertiaryButtonBackground.themed(context.brightness), + padding: const EdgeInsets.all(15), + ), mainButton: ZupPrimaryButton( key: Key("deposit-button-${yieldItem.poolAddress}"), title: S.of(context).yieldCardDeposit, diff --git a/lib/app/create/yields/yields_state.dart b/lib/app/create/yields/yields_state.dart index 2b7bbad..e0a921d 100644 --- a/lib/app/create/yields/yields_state.dart +++ b/lib/app/create/yields/yields_state.dart @@ -4,7 +4,7 @@ part of 'yields_cubit.dart'; abstract class YieldsState with _$YieldsState { const factory YieldsState.initial() = _Initial; const factory YieldsState.loading() = _Loading; - const factory YieldsState.success(YieldsDto yields) = _Success; + const factory YieldsState.success(LiquidityPoolsSearchResultDto yields) = _Success; const factory YieldsState.error(String message, String stackTrace) = _Error; const factory YieldsState.noYields({required PoolSearchFiltersDto filtersApplied}) = _NoYields; } diff --git a/lib/core/concentrated_liquidity_utils/cl_pool_constants.dart b/lib/core/concentrated_liquidity_utils/cl_pool_constants.dart index 8ef3400..7f4d356 100644 --- a/lib/core/concentrated_liquidity_utils/cl_pool_constants.dart +++ b/lib/core/concentrated_liquidity_utils/cl_pool_constants.dart @@ -1,6 +1,11 @@ abstract class CLPoolConstants { static final BigInt minTick = BigInt.from(-887272); + static final BigInt maxTick = -minTick; + static final BigInt q96 = BigInt.from(2).pow(96); + static final BigInt q32 = BigInt.from(2).pow(32); + + static const int feeTierFactor = 10000; } diff --git a/lib/core/dtos/deposit_page_arguments_dto.dart b/lib/core/dtos/deposit_page_arguments_dto.dart index 3393f21..f8cbacc 100644 --- a/lib/core/dtos/deposit_page_arguments_dto.dart +++ b/lib/core/dtos/deposit_page_arguments_dto.dart @@ -1,5 +1,5 @@ import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; part 'deposit_page_arguments_dto.freezed.dart'; part 'deposit_page_arguments_dto.g.dart'; @@ -7,7 +7,7 @@ part 'deposit_page_arguments_dto.g.dart'; @freezed sealed class DepositPageArgumentsDto with _$DepositPageArgumentsDto { @JsonSerializable(explicitToJson: true) - const factory DepositPageArgumentsDto({YieldDto? yieldPool}) = _DepositPageArgumentsDto; + const factory DepositPageArgumentsDto({LiquidityPoolDto? yieldPool}) = _DepositPageArgumentsDto; factory DepositPageArgumentsDto.fromJson(Map json) => _$DepositPageArgumentsDtoFromJson(json); } diff --git a/lib/core/dtos/hook_dto.dart b/lib/core/dtos/hook_dto.dart new file mode 100644 index 0000000..322d3c1 --- /dev/null +++ b/lib/core/dtos/hook_dto.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:web3kit/core/ethereum_constants.dart'; + +part 'hook_dto.freezed.dart'; +part 'hook_dto.g.dart'; + +@freezed +sealed class HookDto with _$HookDto { + @JsonSerializable(explicitToJson: true) + const factory HookDto({@Default(EthereumConstants.zeroAddress) String address, @Default(false) bool isDynamicFee}) = + _HookDto; + + factory HookDto.fromJson(Map json) => _$HookDtoFromJson(json); + + factory HookDto.fixture() => const HookDto(address: EthereumConstants.zeroAddress, isDynamicFee: false); +} diff --git a/lib/core/dtos/liquidity_pool_dto.dart b/lib/core/dtos/liquidity_pool_dto.dart new file mode 100644 index 0000000..b5626c4 --- /dev/null +++ b/lib/core/dtos/liquidity_pool_dto.dart @@ -0,0 +1,157 @@ +import 'package:clock/clock.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:web3kit/core/ethereum_constants.dart'; +import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_constants.dart'; +import 'package:zup_app/core/dtos/hook_dto.dart'; +import 'package:zup_app/core/dtos/pool_stats_dto.dart'; +import 'package:zup_app/core/dtos/protocol_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; +import 'package:zup_app/core/enums/networks.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; +import 'package:zup_app/core/enums/pool_type.dart'; +import 'package:zup_app/core/extensions/num_extension.dart'; + +part 'liquidity_pool_dto.freezed.dart'; +part 'liquidity_pool_dto.g.dart'; + +@freezed +sealed class LiquidityPoolDto with _$LiquidityPoolDto { + const LiquidityPoolDto._(); + @JsonSerializable(explicitToJson: true) + const factory LiquidityPoolDto({ + required SingleChainTokenDto token0, + required SingleChainTokenDto token1, + required String poolAddress, + required String positionManagerAddress, + required int tickSpacing, + required ProtocolDto protocol, + required int initialFeeTier, + required int currentFeeTier, + required int chainId, + PoolTotalStatsDTO? total24hStats, + PoolTotalStatsDTO? total7dStats, + PoolTotalStatsDTO? total30dStats, + PoolTotalStatsDTO? total90dStats, + HookDto? hook, + @Default(0) int createdAtTimestamp, + @Default(PoolType.unknown) @JsonKey(unknownEnumValue: PoolType.unknown) PoolType poolType, + @Default("0") String latestTick, + @Default("0") String latestSqrtPriceX96, + @Default(0) num totalValueLockedUSD, + @Default(EthereumConstants.zeroAddress) @JsonKey(name: "deployerAddress") String deployerAddress, + @JsonKey(name: "poolManagerAddress") String? v4PoolManager, + @JsonKey(name: "stateViewAddress") String? v4StateView, + @JsonKey(name: "permit2Address") String? permit2, + }) = _LiquidityPoolDto; + + AppNetworks get network => AppNetworks.fromChainId(chainId)!; + + bool get isToken0Native => token0.address == EthereumConstants.zeroAddress; + bool get isToken1Native => token1.address == EthereumConstants.zeroAddress; + + String get currentFeeTierFormatted { + return "${(currentFeeTier / CLPoolConstants.feeTierFactor)}%"; + } + + bool get isDynamicFee => hook?.isDynamicFee ?? false; + + int get createdAtMillisecondsTimestamp => createdAtTimestamp * 1000; + + String timeframedYieldFormatted(PoolDataTimeframe yieldTimeFrame) { + switch (yieldTimeFrame) { + case PoolDataTimeframe.day: + return total24hStats?.yearlyYield == 0 ? "-" : total24hStats?.yearlyYield.formatRoundingPercent ?? "-"; + case PoolDataTimeframe.week: + return total7dStats?.yearlyYield == 0 ? "-" : total7dStats?.yearlyYield.formatRoundingPercent ?? "-"; + case PoolDataTimeframe.month: + return total30dStats?.yearlyYield == 0 ? "-" : total30dStats?.yearlyYield.formatRoundingPercent ?? "-"; + case PoolDataTimeframe.threeMonth: + return total90dStats?.yearlyYield == 0 ? "-" : total90dStats?.yearlyYield.formatRoundingPercent ?? "-"; + } + } + + num volumeTimeframed(PoolDataTimeframe yieldTimeFrame) { + switch (yieldTimeFrame) { + case PoolDataTimeframe.day: + return total24hStats?.totalVolume ?? 0; + case PoolDataTimeframe.week: + return total7dStats?.totalVolume ?? 0; + case PoolDataTimeframe.month: + return total30dStats?.totalVolume ?? 0; + case PoolDataTimeframe.threeMonth: + return total90dStats?.totalVolume ?? 0; + } + } + + num feesTimeframed(PoolDataTimeframe yieldTimeFrame) { + switch (yieldTimeFrame) { + case PoolDataTimeframe.day: + return total24hStats?.totalFees ?? 0; + case PoolDataTimeframe.week: + return total7dStats?.totalFees ?? 0; + case PoolDataTimeframe.month: + return total30dStats?.totalFees ?? 0; + case PoolDataTimeframe.threeMonth: + return total90dStats?.totalFees ?? 0; + } + } + + num netInflowTimeframed(PoolDataTimeframe yieldTimeFrame) { + switch (yieldTimeFrame) { + case PoolDataTimeframe.day: + return total24hStats?.totalNetInflow ?? 0; + case PoolDataTimeframe.week: + return total7dStats?.totalNetInflow ?? 0; + case PoolDataTimeframe.month: + return total30dStats?.totalNetInflow ?? 0; + case PoolDataTimeframe.threeMonth: + return total90dStats?.totalNetInflow ?? 0; + } + } + + num yieldTimeframed(PoolDataTimeframe yieldTimeFrame) { + switch (yieldTimeFrame) { + case PoolDataTimeframe.day: + return total24hStats?.yearlyYield ?? 0; + case PoolDataTimeframe.week: + return total7dStats?.yearlyYield ?? 0; + case PoolDataTimeframe.month: + return total30dStats?.yearlyYield ?? 0; + case PoolDataTimeframe.threeMonth: + return total90dStats?.yearlyYield ?? 0; + } + } + + factory LiquidityPoolDto.fromJson(Map json) => _$LiquidityPoolDtoFromJson(json); + + factory LiquidityPoolDto.fixture() => LiquidityPoolDto( + initialFeeTier: 0, + currentFeeTier: 0, + createdAtTimestamp: (clock.now().copyWith(year: 2024, month: 2, day: 23).millisecondsSinceEpoch / 1000).toInt(), + total24hStats: PoolTotalStatsDTO.fixture(), + total7dStats: PoolTotalStatsDTO.fixture(), + total30dStats: PoolTotalStatsDTO.fixture(), + total90dStats: PoolTotalStatsDTO.fixture(), + latestTick: "1567241", + positionManagerAddress: "0x5Df2f0aFb5b5bB2Df9D1e9C7b6f5f0DD5f9eD5e0", + poolAddress: "0x5Df2f0aFb5b5bB2Df9D1e9C7b6f5f0DD5f9eD5e0", + poolType: PoolType.v3, + token0: SingleChainTokenDto.fixture().copyWith( + symbol: "USDC", + decimals: 6, + address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + logoUrl: + "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png", + ), + token1: SingleChainTokenDto.fixture().copyWith( + symbol: "WETH", + decimals: 18, + address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + logoUrl: + "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png", + ), + tickSpacing: 10, + protocol: ProtocolDto.fixture(), + chainId: AppNetworks.sepolia.chainId, + ); +} diff --git a/lib/core/dtos/liquidity_pools_search_result_dto.dart b/lib/core/dtos/liquidity_pools_search_result_dto.dart new file mode 100644 index 0000000..50487c3 --- /dev/null +++ b/lib/core/dtos/liquidity_pools_search_result_dto.dart @@ -0,0 +1,105 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/dtos/pool_search_filters_dto.dart'; +import 'package:zup_app/core/dtos/pool_stats_dto.dart'; +import 'package:zup_app/core/dtos/protocol_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; +import 'package:zup_app/core/enums/pool_type.dart'; +import 'package:zup_app/core/enums/protocol_id.dart'; + +part 'liquidity_pools_search_result_dto.freezed.dart'; +part 'liquidity_pools_search_result_dto.g.dart'; + +@freezed +sealed class LiquidityPoolsSearchResultDto with _$LiquidityPoolsSearchResultDto { + const LiquidityPoolsSearchResultDto._(); + + @JsonSerializable(explicitToJson: true) + const factory LiquidityPoolsSearchResultDto({ + @Default([]) @JsonKey(name: "pools") List pools, + @Default(PoolSearchFiltersDto()) PoolSearchFiltersDto filters, + }) = _LiquidityPoolsSearchResultDto; + + bool get isEmpty => pools.isEmpty; + + List get poolsSortedBy24hYield { + return [...pools]..sort((a, b) => b.total24hStats?.yearlyYield.compareTo(a.total24hStats?.yearlyYield ?? 0) ?? 0); + } + + List get poolsSortedBy7dYield { + return [...pools]..sort((a, b) => b.total7dStats?.yearlyYield.compareTo(a.total7dStats?.yearlyYield ?? 0) ?? 0); + } + + List get poolsSortedBy30dYield { + return [...pools]..sort((a, b) => b.total30dStats?.yearlyYield.compareTo(a.total30dStats?.yearlyYield ?? 0) ?? 0); + } + + List get poolsSortedBy90dYield { + return [...pools]..sort((a, b) => b.total90dStats?.yearlyYield.compareTo(a.total90dStats?.yearlyYield ?? 0) ?? 0); + } + + List poolsSortedByTimeframe(PoolDataTimeframe timeframe) { + switch (timeframe) { + case PoolDataTimeframe.day: + return poolsSortedBy24hYield; + case PoolDataTimeframe.week: + return poolsSortedBy7dYield; + case PoolDataTimeframe.month: + return poolsSortedBy30dYield; + case PoolDataTimeframe.threeMonth: + return poolsSortedBy90dYield; + } + } + + factory LiquidityPoolsSearchResultDto.fromJson(Map json) => + _$LiquidityPoolsSearchResultDtoFromJson(json); + + factory LiquidityPoolsSearchResultDto.empty() => const LiquidityPoolsSearchResultDto(pools: []); + + factory LiquidityPoolsSearchResultDto.fixture() => LiquidityPoolsSearchResultDto( + filters: PoolSearchFiltersDto.fixture(), + pools: [ + LiquidityPoolDto( + createdAtTimestamp: DateTime(1992).millisecondsSinceEpoch, + latestTick: "637812562", + latestSqrtPriceX96: "5240418162556390792557189", + positionManagerAddress: "0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4", + poolType: PoolType.v3, + total24hStats: PoolTotalStatsDTO.fixture(), + total7dStats: PoolTotalStatsDTO.fixture(), + total30dStats: PoolTotalStatsDTO.fixture(), + total90dStats: PoolTotalStatsDTO.fixture(), + token0: const SingleChainTokenDto( + address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + decimals: 18, + name: "Wrapped Ether", + symbol: "WETH", + logoUrl: + "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/scroll/assets/0x5300000000000000000000000000000000000004/logo.png", + ), + token1: const SingleChainTokenDto( + address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", + decimals: 6, + logoUrl: + "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/scroll/assets/0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4/logo.png", + name: "USDC", + symbol: "USDC", + ), + chainId: 1, + poolAddress: "0x4040CE732c1A538A4Ac3157FDC35179D73ea76cd", + tickSpacing: 10, + + totalValueLockedUSD: 65434567890.21, + initialFeeTier: 500, + currentFeeTier: 500, + protocol: ProtocolDto( + id: ProtocolId.pancakeSwapInfinityCL, + rawId: ProtocolId.pancakeSwapInfinityCL.toRawJsonValue, + name: "PancakeSwap", + logo: "https://raw.githubusercontent.com/trustwallet/assets/master/dapps/exchange.pancakeswap.finance.png", + ), + ), + ], + ); +} diff --git a/lib/core/dtos/multi_chain_token_dto.dart b/lib/core/dtos/multi_chain_token_dto.dart new file mode 100644 index 0000000..03a51c1 --- /dev/null +++ b/lib/core/dtos/multi_chain_token_dto.dart @@ -0,0 +1,39 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:zup_app/core/enums/networks.dart'; + +part 'multi_chain_token_dto.freezed.dart'; +part 'multi_chain_token_dto.g.dart'; + +@freezed +sealed class MultiChainTokenDto with _$MultiChainTokenDto { + @JsonSerializable(explicitToJson: true) + const factory MultiChainTokenDto({ + @JsonKey(name: "id") String? internalId, + @Default("") String symbol, + @Default("") String name, + @Default("") String logoUrl, + @Default({}) Map addresses, + @Default({}) Map decimals, + }) = _MultiChainTokenDto; + + factory MultiChainTokenDto.fromJson(Map json) => _$MultiChainTokenDtoFromJson(json); + + factory MultiChainTokenDto.empty() => const MultiChainTokenDto(); + + factory MultiChainTokenDto.fixture() => MultiChainTokenDto( + symbol: 'WETH', + name: 'Wrapped Ether', + decimals: Map.fromEntries( + AppNetworks.values.where((network) => !network.isAllNetworks).map((network) { + return MapEntry(network.chainId, 18); + }), + ), + addresses: Map.fromEntries( + AppNetworks.values.where((network) => !network.isAllNetworks).map((network) { + return MapEntry(network.chainId, "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"); + }), + ), + logoUrl: + 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png', + ); +} diff --git a/lib/core/dtos/pool_search_filters_dto.dart b/lib/core/dtos/pool_search_filters_dto.dart index 4c589d1..11bcf6f 100644 --- a/lib/core/dtos/pool_search_filters_dto.dart +++ b/lib/core/dtos/pool_search_filters_dto.dart @@ -6,21 +6,13 @@ part 'pool_search_filters_dto.g.dart'; @freezed sealed class PoolSearchFiltersDto with _$PoolSearchFiltersDto { @JsonSerializable(explicitToJson: true) - const factory PoolSearchFiltersDto({ - @Default(0) num minTvlUsd, - @Default(false) bool testnetMode, - @Default([]) List allowedPoolTypes, - @Default([]) List blockedProtocols, - }) = _PoolSearchFiltersDto; + const factory PoolSearchFiltersDto({@Default(0) num minTvlUsd, @Default([]) List blockedProtocols}) = + _PoolSearchFiltersDto; const PoolSearchFiltersDto._(); factory PoolSearchFiltersDto.fromJson(Map json) => _$PoolSearchFiltersDtoFromJson(json); - factory PoolSearchFiltersDto.fixture() => const PoolSearchFiltersDto( - allowedPoolTypes: ["V3", "V4"], - blockedProtocols: ["nuri-exchange"], - minTvlUsd: 121782617, - testnetMode: false, - ); + factory PoolSearchFiltersDto.fixture() => + const PoolSearchFiltersDto(blockedProtocols: ["nuri-exchange"], minTvlUsd: 121782617); } diff --git a/lib/core/dtos/pool_search_settings_dto.dart b/lib/core/dtos/pool_search_settings_dto.dart index 6846618..e14edfe 100644 --- a/lib/core/dtos/pool_search_settings_dto.dart +++ b/lib/core/dtos/pool_search_settings_dto.dart @@ -10,8 +10,6 @@ sealed class PoolSearchSettingsDto with _$PoolSearchSettingsDto { @JsonSerializable(explicitToJson: true) factory PoolSearchSettingsDto({ @Default(PoolSearchSettingsDto.defaultMinLiquidityUSD) @JsonKey(name: 'min_liquidity_usd') num minLiquidityUSD, - @Default(true) bool allowV4Search, - @Default(true) bool allowV3Search, }) = _PoolSearchSettingsDto; const PoolSearchSettingsDto._(); diff --git a/lib/core/dtos/pool_stats_dto.dart b/lib/core/dtos/pool_stats_dto.dart new file mode 100644 index 0000000..3cf0f04 --- /dev/null +++ b/lib/core/dtos/pool_stats_dto.dart @@ -0,0 +1,19 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'pool_stats_dto.freezed.dart'; +part 'pool_stats_dto.g.dart'; + +@freezed +sealed class PoolTotalStatsDTO with _$PoolTotalStatsDTO { + @JsonSerializable(explicitToJson: true) + const factory PoolTotalStatsDTO({ + @Default(0) num totalVolume, + @Default(0) num totalFees, + @Default(0) @JsonKey(name: "yield") num yearlyYield, + @Default(0) num totalNetInflow, + }) = _PoolTotalStatsDTO; + + factory PoolTotalStatsDTO.fromJson(Map json) => _$PoolTotalStatsDTOFromJson(json); + + factory PoolTotalStatsDTO.fixture() => const PoolTotalStatsDTO(totalVolume: 100, totalFees: 10, yearlyYield: 10); +} diff --git a/lib/core/dtos/position_dto.dart b/lib/core/dtos/position_dto.dart deleted file mode 100644 index fb9e012..0000000 --- a/lib/core/dtos/position_dto.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:zup_app/core/dtos/protocol_dto.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/enums/networks.dart'; -import 'package:zup_app/core/enums/position_status.dart'; - -part 'position_dto.freezed.dart'; -part 'position_dto.g.dart'; - -@freezed -sealed class PositionDto with _$PositionDto { - const PositionDto._(); - - @JsonSerializable(explicitToJson: true) - const factory PositionDto({ - TokenDto? token0, - TokenDto? token1, - @Default(null) AppNetworks? network, - @Default(PositionStatus.unknown) @JsonKey(unknownEnumValue: PositionStatus.unknown) PositionStatus status, - @Default(null) ProtocolDto? protocol, - @Default(0) num minRange, - @Default(0) num maxRange, - @Default(0) @JsonKey(name: "liquidity") num liquidityUSD, - @Default(0) @JsonKey(name: 'unclaimed_fees') num unclaimedFeesUSD, - }) = _PositionDto; - - factory PositionDto.fromJson(Map json) => _$PositionDtoFromJson(json); - - factory PositionDto.fixture() => PositionDto( - liquidityUSD: 123543.43, - minRange: 0.4, - maxRange: 123413.43, - status: PositionStatus.inRange, - token0: TokenDto.fixture(), - token1: TokenDto.fixture(), - protocol: ProtocolDto.fixture(), - unclaimedFeesUSD: 1543.43, - ); -} diff --git a/lib/core/dtos/protocol_dto.dart b/lib/core/dtos/protocol_dto.dart index b61682d..7c354e5 100644 --- a/lib/core/dtos/protocol_dto.dart +++ b/lib/core/dtos/protocol_dto.dart @@ -24,8 +24,8 @@ sealed class ProtocolDto with _$ProtocolDto { factory ProtocolDto.fixture() => ProtocolDto( rawId: ProtocolId.velodromeSlipstream.toRawJsonValue, id: ProtocolId.velodromeSlipstream, - name: "Uniswap", + name: "Uniswap V3", url: "https://app.uniswap.org/pool", - logo: "https://raw.githubusercontent.com/trustwallet/assets/master/dapps/app.uniswap.org.png", + logo: "https://assets-cdn.trustwallet.com/dapps/app.uniswap.org.png", ); } diff --git a/lib/core/dtos/single_chain_token_dto.dart b/lib/core/dtos/single_chain_token_dto.dart new file mode 100644 index 0000000..047cc97 --- /dev/null +++ b/lib/core/dtos/single_chain_token_dto.dart @@ -0,0 +1,25 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'single_chain_token_dto.freezed.dart'; +part 'single_chain_token_dto.g.dart'; + +@freezed +sealed class SingleChainTokenDto with _$SingleChainTokenDto { + @JsonSerializable(explicitToJson: true) + const factory SingleChainTokenDto({ + required String address, + @Default(18) int decimals, + @Default("") String name, + @Default("") String symbol, + @Default("") String logoUrl, + }) = _SingleChainTokenDto; + + factory SingleChainTokenDto.fromJson(Map json) => _$SingleChainTokenDtoFromJson(json); + + factory SingleChainTokenDto.fixture() => const SingleChainTokenDto( + address: '0x0000000000000000000000000000000000000000', + decimals: 18, + name: 'Test Token', + symbol: 'TEST', + ); +} diff --git a/lib/core/dtos/token_dto.dart b/lib/core/dtos/token_dto.dart deleted file mode 100644 index 7cbf435..0000000 --- a/lib/core/dtos/token_dto.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:zup_app/core/enums/networks.dart'; - -part 'token_dto.freezed.dart'; -part 'token_dto.g.dart'; - -@freezed -sealed class TokenDto with _$TokenDto { - @JsonSerializable(explicitToJson: true) - const factory TokenDto({ - @JsonKey(name: "id") String? internalId, - @Default("") String symbol, - @Default("") String name, - @Default("") String logoUrl, - @Default({}) Map addresses, - @Default({}) Map decimals, - }) = _TokenDto; - - factory TokenDto.fromJson(Map json) => _$TokenDtoFromJson(json); - - factory TokenDto.empty() => const TokenDto(); - - factory TokenDto.fixture() => TokenDto( - symbol: 'WETH', - name: 'Wrapped Ether', - decimals: Map.fromEntries( - AppNetworks.values.where((network) => !network.isAllNetworks).map( - (network) { - return MapEntry(network.chainId, 18); - }, - ), - ), - addresses: Map.fromEntries( - AppNetworks.values.where((network) => !network.isAllNetworks).map( - (network) { - return MapEntry(network.chainId, "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"); - }, - ), - ), - logoUrl: - 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png', - ); -} diff --git a/lib/core/dtos/token_group_dto.dart b/lib/core/dtos/token_group_dto.dart index 689e235..74292b6 100644 --- a/lib/core/dtos/token_group_dto.dart +++ b/lib/core/dtos/token_group_dto.dart @@ -1,5 +1,5 @@ import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/enums/app_environment.dart'; part 'token_group_dto.freezed.dart'; @@ -13,7 +13,7 @@ sealed class TokenGroupDto with _$TokenGroupDto { const factory TokenGroupDto({ @Default("") String id, @Default("") String name, - @Default([]) List tokens, + @Default([]) List tokens, }) = _TokenGroupDto; String get logoUrl => "${AppEnvironment.current.apiUrl}/static/group-icons/$id.png"; @@ -21,5 +21,5 @@ sealed class TokenGroupDto with _$TokenGroupDto { factory TokenGroupDto.fromJson(Map json) => _$TokenGroupDtoFromJson(json); factory TokenGroupDto.fixture() => - TokenGroupDto(id: "usd-stablecoins-group", name: "USD Stablecoins", tokens: [TokenDto.fixture()]); + TokenGroupDto(id: "usd-stablecoins-group", name: "USD Stablecoins", tokens: [MultiChainTokenDto.fixture()]); } diff --git a/lib/core/dtos/token_list_dto.dart b/lib/core/dtos/token_list_dto.dart index 7d89bab..02a3fc6 100644 --- a/lib/core/dtos/token_list_dto.dart +++ b/lib/core/dtos/token_list_dto.dart @@ -1,5 +1,5 @@ import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/dtos/token_group_dto.dart'; part 'token_list_dto.freezed.dart'; @@ -10,17 +10,11 @@ sealed class TokenListDto with _$TokenListDto { @JsonSerializable(explicitToJson: true) const factory TokenListDto({ @Default([]) List tokenGroups, - @Default([]) List popularTokens, + @Default([]) List popularTokens, }) = _TokenListDto; factory TokenListDto.fromJson(Map json) => _$TokenListDtoFromJson(json); - factory TokenListDto.fixture() => TokenListDto( - popularTokens: [ - TokenDto.fixture(), - ], - tokenGroups: [ - TokenGroupDto.fixture(), - ], - ); + factory TokenListDto.fixture() => + TokenListDto(popularTokens: [MultiChainTokenDto.fixture()], tokenGroups: [TokenGroupDto.fixture()]); } diff --git a/lib/core/dtos/yield_dto.dart b/lib/core/dtos/yield_dto.dart deleted file mode 100644 index 8d7685c..0000000 --- a/lib/core/dtos/yield_dto.dart +++ /dev/null @@ -1,107 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:web3kit/core/ethereum_constants.dart'; -import 'package:zup_app/core/dtos/protocol_dto.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/enums/networks.dart'; -import 'package:zup_app/core/enums/pool_type.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; -import 'package:zup_app/core/extensions/num_extension.dart'; - -part 'yield_dto.freezed.dart'; -part 'yield_dto.g.dart'; - -@freezed -sealed class YieldDto with _$YieldDto { - const YieldDto._(); - @JsonSerializable(explicitToJson: true) - const factory YieldDto({ - required TokenDto token0, - required TokenDto token1, - required String poolAddress, - required String positionManagerAddress, - required int tickSpacing, - required ProtocolDto protocol, - required int initialFeeTier, - required int currentFeeTier, - required int chainId, - @Default(0) num yield24h, - @Default(0) num yield7d, - @Default(0) num yield30d, - @Default(0) num yield90d, - @Default(PoolType.unknown) @JsonKey(unknownEnumValue: PoolType.unknown) PoolType poolType, - @Default("0") String latestTick, - @Default("0") String latestSqrtPriceX96, - @Default(0) num totalValueLockedUSD, - @Default(EthereumConstants.zeroAddress) @JsonKey(name: "hooksAddress") String v4Hooks, - @Default(EthereumConstants.zeroAddress) @JsonKey(name: "deployerAddress") String deployerAddress, - @JsonKey(name: "poolManagerAddress") String? v4PoolManager, - @JsonKey(name: "stateViewAddress") String? v4StateView, - @JsonKey(name: "permit2Address") String? permit2, - }) = _YieldDto; - - AppNetworks get network => AppNetworks.fromChainId(chainId)!; - - bool get isToken0Native => token0.addresses[network.chainId] == EthereumConstants.zeroAddress; - bool get isToken1Native => token1.addresses[network.chainId] == EthereumConstants.zeroAddress; - - int get token0NetworkDecimals => token0.decimals[network.chainId]!; - int get token1NetworkDecimals => token1.decimals[network.chainId]!; - - String timeframedYieldFormatted(YieldTimeFrame yieldTimeFrame) { - switch (yieldTimeFrame) { - case YieldTimeFrame.day: - return yield24h == 0 ? "-" : yield24h.formatPercent; - case YieldTimeFrame.week: - return yield7d == 0 ? "-" : yield7d.formatPercent; - case YieldTimeFrame.month: - return yield30d == 0 ? "-" : yield30d.formatPercent; - case YieldTimeFrame.threeMonth: - return yield90d == 0 ? "-" : yield90d.formatPercent; - } - } - - num yieldTimeframed(YieldTimeFrame yieldTimeFrame) { - switch (yieldTimeFrame) { - case YieldTimeFrame.day: - return yield24h; - case YieldTimeFrame.week: - return yield7d; - case YieldTimeFrame.month: - return yield30d; - case YieldTimeFrame.threeMonth: - return yield90d; - } - } - - factory YieldDto.fromJson(Map json) => _$YieldDtoFromJson(json); - - factory YieldDto.fixture() => YieldDto( - initialFeeTier: 0, - currentFeeTier: 0, - yield24h: 32.2, - yield30d: 32.2, - yield90d: 32.2, - yield7d: 12, - latestTick: "1567241", - positionManagerAddress: "0x5Df2f0aFb5b5bB2Df9D1e9C7b6f5f0DD5f9eD5e0", - poolAddress: "0x5Df2f0aFb5b5bB2Df9D1e9C7b6f5f0DD5f9eD5e0", - poolType: PoolType.v3, - token0: TokenDto.fixture().copyWith( - symbol: "USDC", - decimals: {AppNetworks.sepolia.chainId: 6}, - addresses: {AppNetworks.sepolia.chainId: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"}, - logoUrl: - "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png", - ), - token1: TokenDto.fixture().copyWith( - symbol: "WETH", - decimals: {AppNetworks.sepolia.chainId: 18}, - addresses: {AppNetworks.sepolia.chainId: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"}, - logoUrl: - "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png", - ), - tickSpacing: 10, - protocol: ProtocolDto.fixture(), - chainId: AppNetworks.sepolia.chainId, - ); -} diff --git a/lib/core/dtos/yields_dto.dart b/lib/core/dtos/yields_dto.dart deleted file mode 100644 index c03d0b8..0000000 --- a/lib/core/dtos/yields_dto.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:zup_app/core/dtos/pool_search_filters_dto.dart'; -import 'package:zup_app/core/dtos/protocol_dto.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; -import 'package:zup_app/core/enums/pool_type.dart'; -import 'package:zup_app/core/enums/protocol_id.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; - -part 'yields_dto.freezed.dart'; -part 'yields_dto.g.dart'; - -@freezed -sealed class YieldsDto with _$YieldsDto { - const YieldsDto._(); - - @JsonSerializable(explicitToJson: true) - const factory YieldsDto({ - @Default([]) @JsonKey(name: "pools") List pools, - @Default(PoolSearchFiltersDto()) PoolSearchFiltersDto filters, - }) = _YieldsDto; - - bool get isEmpty => pools.isEmpty; - - List get poolsSortedBy24hYield { - return [...pools]..sort((a, b) => b.yield24h.compareTo(a.yield24h)); - } - - List get poolsSortedBy7dYield { - return [...pools]..sort((a, b) => b.yield7d.compareTo(a.yield7d)); - } - - List get poolsSortedBy30dYield { - return [...pools]..sort((a, b) => b.yield30d.compareTo(a.yield30d)); - } - - List get poolsSortedBy90dYield { - return [...pools]..sort((a, b) => b.yield90d.compareTo(a.yield90d)); - } - - List poolsSortedByTimeframe(YieldTimeFrame timeframe) { - switch (timeframe) { - case YieldTimeFrame.day: - return poolsSortedBy24hYield; - case YieldTimeFrame.week: - return poolsSortedBy7dYield; - case YieldTimeFrame.month: - return poolsSortedBy30dYield; - case YieldTimeFrame.threeMonth: - return poolsSortedBy90dYield; - } - } - - factory YieldsDto.fromJson(Map json) => _$YieldsDtoFromJson(json); - - factory YieldsDto.empty() => const YieldsDto(pools: []); - - factory YieldsDto.fixture() => YieldsDto( - filters: PoolSearchFiltersDto.fixture(), - pools: [ - YieldDto( - latestTick: "637812562", - latestSqrtPriceX96: "5240418162556390792557189", - positionManagerAddress: "0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4", - poolType: PoolType.v3, - yield7d: 21, - token0: const TokenDto( - addresses: {1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 "}, - decimals: {1: 18}, - name: "Wrapped Ether", - symbol: "WETH", - logoUrl: - "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/scroll/assets/0x5300000000000000000000000000000000000004/logo.png", - ), - token1: const TokenDto( - addresses: {1: "0xdAC17F958D2ee523a2206206994597C13D831ec7"}, - decimals: {1: 6}, - logoUrl: - "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/scroll/assets/0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4/logo.png", - name: "USDC", - symbol: "USDC", - ), - chainId: 1, - poolAddress: "0x4040CE732c1A538A4Ac3157FDC35179D73ea76cd", - tickSpacing: 10, - yield24h: 1732.42, - yield30d: 765.61, - yield90d: 2022.99, - totalValueLockedUSD: 65434567890.21, - initialFeeTier: 500, - currentFeeTier: 500, - protocol: ProtocolDto( - id: ProtocolId.pancakeSwapInfinityCL, - rawId: ProtocolId.pancakeSwapInfinityCL.toRawJsonValue, - name: "PancakeSwap", - logo: "https://raw.githubusercontent.com/trustwallet/assets/master/dapps/exchange.pancakeswap.finance.png", - ), - ), - ], - ); -} diff --git a/lib/core/enums/networks.dart b/lib/core/enums/networks.dart index b50bacd..9daa081 100644 --- a/lib/core/enums/networks.dart +++ b/lib/core/enums/networks.dart @@ -155,10 +155,39 @@ enum AppNetworks { // bnb => "https://bsc-rpc.publicnode.com" }; + String get websiteUrl => switch (this) { + allNetworks => throw UnimplementedError("allNetworks is not a valid network"), + sepolia => "https://ethereum.org", + mainnet => "https://ethereum.org", + scroll => "https://scroll.io", + base => "https://base.org", + unichain => "https://www.unichain.org", + hyperEvm => "https://hyperfoundation.org", + plasma => "https://www.plasma.to", + }; + + String? get dexscreenerUrl => switch (this) { + allNetworks => null, + sepolia => null, + mainnet => "https://dexscreener.com/ethereum", + scroll => "https://dexscreener.com/scroll", + base => "https://dexscreener.com/base", + unichain => "https://dexscreener.com/unichain", + hyperEvm => "https://dexscreener.com/hyperevm", + plasma => "https://dexscreener.com/plasma", + }; + Future openTx(String txHash) async { final url = "${chainInfo.blockExplorerUrls?.first}/tx/$txHash"; if (!await canLaunchUrl(Uri.parse(url))) return; await launchUrl(Uri.parse(url)); } + + Future openAddress(String address) async { + final url = "${chainInfo.blockExplorerUrls?.first}/address/$address"; + if (!await canLaunchUrl(Uri.parse(url))) return; + + await launchUrl(Uri.parse(url)); + } } diff --git a/lib/core/enums/pool_data_timeframe.dart b/lib/core/enums/pool_data_timeframe.dart new file mode 100644 index 0000000..8a3e29f --- /dev/null +++ b/lib/core/enums/pool_data_timeframe.dart @@ -0,0 +1,37 @@ +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart'; +import 'package:zup_app/l10n/gen/app_localizations.dart'; + +enum PoolDataTimeframe { + day, + week, + month, + threeMonth; + + static PoolDataTimeframe? fromValue(String name) { + return PoolDataTimeframe.values.firstWhereOrNull((e) => e.name == name); + } +} + +extension YieldTimeFrameExtension on PoolDataTimeframe { + bool get isDay => this == PoolDataTimeframe.day; + bool get isWeek => this == PoolDataTimeframe.week; + bool get isMonth => this == PoolDataTimeframe.month; + bool get isThreeMonth => this == PoolDataTimeframe.threeMonth; + + String label(BuildContext context) { + return switch (this) { + PoolDataTimeframe.day => S.of(context).twentyFourHours, + PoolDataTimeframe.week => S.of(context).week, + PoolDataTimeframe.month => S.of(context).month, + PoolDataTimeframe.threeMonth => S.of(context).threeMonths, + }; + } + + String compactDaysLabel(BuildContext context) => switch (this) { + PoolDataTimeframe.day => S.of(context).twentyFourHoursCompact, + PoolDataTimeframe.week => S.of(context).weekCompact, + PoolDataTimeframe.month => S.of(context).monthCompact, + PoolDataTimeframe.threeMonth => S.of(context).threeMonthsCompact, + }; +} diff --git a/lib/core/enums/pool_type.dart b/lib/core/enums/pool_type.dart index 9690241..297e002 100644 --- a/lib/core/enums/pool_type.dart +++ b/lib/core/enums/pool_type.dart @@ -1,4 +1,6 @@ +import 'package:flutter/widgets.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:zup_app/l10n/gen/app_localizations.dart'; enum PoolType { @JsonValue("V3") @@ -11,8 +13,14 @@ enum PoolType { bool get isV4 => this == PoolType.v4; String get label => switch (this) { - PoolType.v3 => "V3", - PoolType.v4 => "V4", - PoolType.unknown => "Unknown", - }; + PoolType.v3 => "V3", + PoolType.v4 => "V4", + PoolType.unknown => "Unknown", + }; + + String description(BuildContext context) => switch (this) { + PoolType.v3 => S.of(context).poolTypeV3Description, + PoolType.v4 => S.of(context).poolTypeV4Description, + PoolType.unknown => "", + }; } diff --git a/lib/core/enums/protocol_id.dart b/lib/core/enums/protocol_id.dart index 4edb50d..8a054e8 100644 --- a/lib/core/enums/protocol_id.dart +++ b/lib/core/enums/protocol_id.dart @@ -14,6 +14,8 @@ enum ProtocolId { gliquidV3, @JsonValue("kittenswap-v3") kittenswapV3, + @JsonValue("hx-finance-algebra") + hxFinanceAlgebra, unknown; bool get isPancakeSwapInfinityCL => this == ProtocolId.pancakeSwapInfinityCL; @@ -21,7 +23,9 @@ enum ProtocolId { (this == ProtocolId.aerodromeSlipstream || this == ProtocolId.velodromeSlipstream); bool get isGLiquidV3 => this == ProtocolId.gliquidV3; bool get isKittenswapV3 => this == ProtocolId.kittenswapV3; - bool get isAlgebra1_2 => isGLiquidV3 || isKittenswapV3; + bool get isHxFinanceAlgebra => this == ProtocolId.hxFinanceAlgebra; + + bool get isAlgebra1_2 => isGLiquidV3 || isKittenswapV3 || isHxFinanceAlgebra; String get toRawJsonValue => _$ProtocolIdEnumMap[this]!; } diff --git a/lib/core/enums/yield_timeframe.dart b/lib/core/enums/yield_timeframe.dart deleted file mode 100644 index bcc0c73..0000000 --- a/lib/core/enums/yield_timeframe.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:collection/collection.dart'; -import 'package:flutter/material.dart'; -import 'package:zup_app/l10n/gen/app_localizations.dart'; - -enum YieldTimeFrame { - day, - week, - month, - threeMonth; - - static YieldTimeFrame? fromValue(String name) { - return YieldTimeFrame.values.firstWhereOrNull((e) => e.name == name); - } -} - -extension YieldTimeFrameExtension on YieldTimeFrame { - bool get isDay => this == YieldTimeFrame.day; - bool get isWeek => this == YieldTimeFrame.week; - bool get isMonth => this == YieldTimeFrame.month; - bool get isThreeMonth => this == YieldTimeFrame.threeMonth; - - String label(BuildContext context) { - return switch (this) { - YieldTimeFrame.day => S.of(context).twentyFourHours, - YieldTimeFrame.week => S.of(context).week, - YieldTimeFrame.month => S.of(context).month, - YieldTimeFrame.threeMonth => S.of(context).threeMonths, - }; - } - - String compactDaysLabel(BuildContext context) => switch (this) { - YieldTimeFrame.day => S.of(context).twentyFourHoursCompact, - YieldTimeFrame.week => S.of(context).weekCompact, - YieldTimeFrame.month => S.of(context).monthCompact, - YieldTimeFrame.threeMonth => S.of(context).threeMonthsCompact, - }; -} diff --git a/lib/core/extensions/list_extension.dart b/lib/core/extensions/list_extension.dart deleted file mode 100644 index d35d0a0..0000000 --- a/lib/core/extensions/list_extension.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:zup_app/core/dtos/yield_dto.dart'; - -extension YieldDTOListExtension on List { - YieldDto get bestYield { - final yieldListClone = List.from(this); - - yieldListClone.sort((a, b) => b.yearlyYield.compareTo(a.yearlyYield)); - return yieldListClone.first; - } -} diff --git a/lib/core/extensions/num_extension.dart b/lib/core/extensions/num_extension.dart index 66c9642..e5a7b1f 100644 --- a/lib/core/extensions/num_extension.dart +++ b/lib/core/extensions/num_extension.dart @@ -44,10 +44,10 @@ extension NumExtension on num { final maxWithoutMoreThan = maxBeforeMoreThan ?? pow(10, 12) * 999; if (useMoreThan && this > maxWithoutMoreThan) { - return NumberFormat.compactCurrency(decimalDigits: decimals, name: ">").format(maxWithoutMoreThan); + return NumberFormat.compactCurrency(decimalDigits: 2, name: ">").format(maxWithoutMoreThan); } - return NumberFormat.compactCurrency(decimalDigits: decimals, name: isUSD ? "USD " : "").format(this); + return NumberFormat.compactCurrency(decimalDigits: 2, name: isUSD ? r"$" : "").format(this); } String maybeFormatCompactCurrency({ @@ -67,8 +67,9 @@ extension NumExtension on num { return formatCurrency(isUSD: isUSD, useLessThan: useLessThan); } - String get formatPercent { + String get formatRoundingPercent { int decimalsDigits = 0; + if (decimals >= 1 && toString().split(".")[1] != "0") decimalsDigits = 1; return "${NumberFormat.decimalPatternDigits(decimalDigits: decimalsDigits).format(this)}%"; diff --git a/lib/core/extensions/time_ago_extension.dart b/lib/core/extensions/time_ago_extension.dart new file mode 100644 index 0000000..90432b6 --- /dev/null +++ b/lib/core/extensions/time_ago_extension.dart @@ -0,0 +1,18 @@ +import 'package:flutter/widgets.dart'; +import 'package:zup_app/l10n/gen/app_localizations.dart'; +import 'package:zup_core/enums/time_unit.dart'; +import 'package:zup_core/objects/time_ago.dart'; + +extension TimeAgoExtension on TimeAgo { + String formattedTimeAgo(BuildContext context) { + return switch (amountTimeUnit) { + TimeUnit.milliseconds => S.of(context).xMillisecondsAgo(milliseconds: amount), + TimeUnit.seconds => S.of(context).xSecondsAgo(seconds: amount), + TimeUnit.minutes => S.of(context).xMinutesAndSecondsAgo(minutes: amount, seconds: remainder), + TimeUnit.hours => S.of(context).xHoursAndMinutesAgo(hours: amount, minutes: remainder), + TimeUnit.days => S.of(context).xDaysAndHoursAgo(days: amount, hours: remainder), + TimeUnit.months => S.of(context).xMonthsAndDaysAgo(months: amount, days: remainder), + TimeUnit.years => S.of(context).xYearsAndMonthsAgo(years: amount, months: remainder), + }; + } +} diff --git a/lib/core/injections.dart b/lib/core/injections.dart index 87d9b79..f2239ac 100644 --- a/lib/core/injections.dart +++ b/lib/core/injections.dart @@ -23,7 +23,6 @@ import 'package:zup_app/core/cache.dart'; import 'package:zup_app/core/debouncer.dart'; import 'package:zup_app/core/enums/app_environment.dart'; import 'package:zup_app/core/pool_service.dart'; -import 'package:zup_app/core/repositories/positions_repository.dart'; import 'package:zup_app/core/repositories/protocol_repository.dart'; import 'package:zup_app/core/repositories/tokens_repository.dart'; import 'package:zup_app/core/repositories/yield_repository.dart'; @@ -32,8 +31,8 @@ import 'package:zup_app/core/zup_links.dart'; import 'package:zup_app/core/zup_navigator.dart'; import 'package:zup_app/gen/assets.gen.dart'; import 'package:zup_app/widgets/token_selector_modal/token_selector_modal_cubit.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; import 'package:zup_core/zup_core.dart'; +import 'package:zup_ui_kit/zup_ui_kit.dart'; final inject = GetIt.instance; @@ -72,8 +71,7 @@ Future setupInjections() async { inject.registerLazySingleton(() => ZupNavigator()); inject.registerLazySingleton(() => Wallet.shared); inject.registerLazySingleton(() => AppCubit(inject(), inject())); - inject.registerLazySingleton(() => PositionsRepository()); - inject.registerLazySingleton(() => ZupCachedImage()); + inject.registerLazySingleton(() => ZupNetworkImage()); inject.registerLazySingleton(() => true, instanceName: InjectInstanceNames.infinityAnimationAutoPlay); inject.registerLazySingleton( () => TokensRepository(inject(instanceName: InjectInstanceNames.zupAPIDio)), diff --git a/lib/core/pool_service.dart b/lib/core/pool_service.dart index 2cdb4f1..6dee5b1 100644 --- a/lib/core/pool_service.dart +++ b/lib/core/pool_service.dart @@ -15,7 +15,7 @@ import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_conversors_mix import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_liquidity_calculations_mixin.dart'; import 'package:zup_app/core/concentrated_liquidity_utils/cl_sqrt_price_math_mixin.dart'; import 'package:zup_app/core/concentrated_liquidity_utils/v4_pool_constants.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; import 'package:zup_app/core/slippage.dart'; class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, CLSqrtPriceMath { @@ -45,7 +45,7 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, this._algebra121PositionManager, ); - Future getPoolTick(YieldDto forYield) async { + Future getPoolTick(LiquidityPoolDto forYield) async { if (forYield.protocol.id.isAlgebra1_2) { final algebraPool = _algebra121Pool.fromRpcProvider( contractAddress: forYield.poolAddress, @@ -90,7 +90,7 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, return (await uniswapV3Pool.slot0()).tick; } - Future getSqrtPriceX96(YieldDto forYield) async { + Future getSqrtPriceX96(LiquidityPoolDto forYield) async { if (forYield.protocol.id.isPancakeSwapInfinityCL) { final pancakeSwapInfinityCLPoolManagerContract = _pancakeSwapInfinityClPoolManager.fromRpcProvider( contractAddress: forYield.v4PoolManager!, @@ -140,7 +140,7 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, } Future sendV3PoolDepositTransaction( - YieldDto depositOnYield, + LiquidityPoolDto depositOnYield, Signer signer, { required BigInt amount0Desired, required BigInt amount1Desired, @@ -250,8 +250,8 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, tickLower: tickLower, tickUpper: tickUpper, fee: BigInt.from(depositOnYield.initialFeeTier), - token0: depositOnYield.token0.addresses[depositOnYield.network.chainId]!, - token1: depositOnYield.token1.addresses[depositOnYield.network.chainId]!, + token0: depositOnYield.token0.address, + token1: depositOnYield.token1.address, ), ); }.call(); @@ -260,7 +260,7 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, } Future sendV4PoolDepositTransaction( - YieldDto depositOnYield, + LiquidityPoolDto depositOnYield, Signer signer, { required Duration deadline, required BigInt tickLower, @@ -337,11 +337,11 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, ], [ [ - depositOnYield.token0.addresses[depositOnYield.network.chainId]!, - depositOnYield.token1.addresses[depositOnYield.network.chainId]!, + depositOnYield.token0.address, + depositOnYield.token1.address, BigInt.from(depositOnYield.initialFeeTier), BigInt.from(depositOnYield.tickSpacing), - depositOnYield.v4Hooks, + depositOnYield.hook?.address ?? EthereumConstants.zeroAddress, ], tickLower, tickUpper, @@ -355,10 +355,7 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, final settlePairActionParams = _ethereumAbiCoder.encode( ["address", "address"], - [ - depositOnYield.token0.addresses[depositOnYield.network.chainId]!, - depositOnYield.token1.addresses[depositOnYield.network.chainId]!, - ], + [depositOnYield.token0.address, depositOnYield.token1.address], ); final sweepActionParams = isNativeDeposit @@ -387,7 +384,7 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, } Future _sendV4PoolDepositTransactionForPancakeSwap( - YieldDto depositOnYield, + LiquidityPoolDto depositOnYield, Signer signer, { required Duration deadline, required BigInt tickLower, @@ -425,9 +422,9 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, ], [ [ - depositOnYield.token0.addresses[depositOnYield.network.chainId]!, - depositOnYield.token1.addresses[depositOnYield.network.chainId]!, - depositOnYield.v4Hooks, + depositOnYield.token0.address, + depositOnYield.token1.address, + depositOnYield.hook?.address ?? EthereumConstants.zeroAddress, depositOnYield.v4PoolManager, depositOnYield.initialFeeTier, await _getPancakeSwapInfinityPoolBytesParameters(depositOnYield), @@ -442,15 +439,9 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, ], ); - final closeCurrency0ActionParams = _ethereumAbiCoder.encode( - ["address"], - [depositOnYield.token0.addresses[depositOnYield.network.chainId]!], - ); + final closeCurrency0ActionParams = _ethereumAbiCoder.encode(["address"], [depositOnYield.token0.address]); - final closeCurrency1ActionParams = _ethereumAbiCoder.encode( - ["address"], - [depositOnYield.token1.addresses[depositOnYield.network.chainId]!], - ); + final closeCurrency1ActionParams = _ethereumAbiCoder.encode(["address"], [depositOnYield.token1.address]); final pancakeSwapV4PositionManagerContract = _pancakeSwapInfinityClPositionManager.fromSigner( contractAddress: depositOnYield.positionManagerAddress, @@ -473,7 +464,7 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, } Future _sendV3DepositTransactionForAlgebra121( - YieldDto depositOnYield, + LiquidityPoolDto depositOnYield, Signer signer, { required BigInt amount0Desired, required BigInt amount1Desired, @@ -527,8 +518,8 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, tickLower: tickLower, tickUpper: tickUpper, deployer: depositOnYield.deployerAddress, - token0: depositOnYield.token0.addresses[depositOnYield.network.chainId]!, - token1: depositOnYield.token1.addresses[depositOnYield.network.chainId]!, + token0: depositOnYield.token0.address, + token1: depositOnYield.token1.address, ), ); }.call(); @@ -537,7 +528,7 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, } Future _sendV3DepositTransactionForSlipstream( - YieldDto depositOnYield, + LiquidityPoolDto depositOnYield, Signer signer, { required BigInt amount0Desired, required BigInt amount1Desired, @@ -593,8 +584,8 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, tickUpper: tickUpper, tickSpacing: BigInt.from(depositOnYield.tickSpacing), sqrtPriceX96: BigInt.from(0), - token0: depositOnYield.token0.addresses[depositOnYield.network.chainId]!, - token1: depositOnYield.token1.addresses[depositOnYield.network.chainId]!, + token0: depositOnYield.token0.address, + token1: depositOnYield.token1.address, ), ); }.call(); @@ -602,17 +593,17 @@ class PoolService with CLPoolLiquidityCalculationsMixin, CLPoolConversorsMixin, return tx; } - String _getNativeV3PoolToken0Address(YieldDto forYield) { + String _getNativeV3PoolToken0Address(LiquidityPoolDto forYield) { if (forYield.isToken0Native) return forYield.network.wrappedNativeTokenAddress; - return forYield.token0.addresses[forYield.network.chainId]!; + return forYield.token0.address; } - String _getNativeV3PoolToken1Address(YieldDto forYield) { + String _getNativeV3PoolToken1Address(LiquidityPoolDto forYield) { if (forYield.isToken1Native) return forYield.network.wrappedNativeTokenAddress; - return forYield.token1.addresses[forYield.network.chainId]!; + return forYield.token1.address; } - Future _getPancakeSwapInfinityPoolBytesParameters(YieldDto forYield) async { + Future _getPancakeSwapInfinityPoolBytesParameters(LiquidityPoolDto forYield) async { final contract = _pancakeSwapInfinityClPoolManager.fromRpcProvider( contractAddress: forYield.v4PoolManager!, rpcUrl: forYield.network.rpcUrl, diff --git a/lib/core/repositories/positions_repository.dart b/lib/core/repositories/positions_repository.dart deleted file mode 100644 index 7ce371e..0000000 --- a/lib/core/repositories/positions_repository.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:zup_app/core/dtos/position_dto.dart'; - -class PositionsRepository { - Future> fetchUserPositions() async { - await Future.delayed(const Duration(seconds: 2)); - return []; - } -} diff --git a/lib/core/repositories/tokens_repository.dart b/lib/core/repositories/tokens_repository.dart index cb28103..728fd4b 100644 --- a/lib/core/repositories/tokens_repository.dart +++ b/lib/core/repositories/tokens_repository.dart @@ -1,5 +1,6 @@ import 'package:dio/dio.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; import 'package:zup_app/core/dtos/token_list_dto.dart'; import 'package:zup_app/core/dtos/token_price_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; @@ -20,28 +21,44 @@ class TokensRepository { return TokenListDto.fromJson(request.data); } - Future> searchToken(String query, AppNetworks network) async { - if (_searchTokenLastCancelToken != null) { - _searchTokenLastCancelToken!.cancel(); - } + Future> searchToken(String query, AppNetworks network) async { + if (_searchTokenLastCancelToken != null) _searchTokenLastCancelToken!.cancel(); _searchTokenLastCancelToken = CancelToken(); - final response = await _zupAPIDio.get( - "/tokens/search", + if (network.isAllNetworks) { + final allNetworksResponse = await _zupAPIDio.get( + "/tokens/search/all", + cancelToken: _searchTokenLastCancelToken, + queryParameters: {"query": query}, + ); + + _searchTokenLastCancelToken = null; + return (allNetworksResponse.data as List).map((token) => MultiChainTokenDto.fromJson(token)).toList(); + } + + final singleNetworkResponse = await _zupAPIDio.get( + "/tokens/search/${network.chainId}", cancelToken: _searchTokenLastCancelToken, - queryParameters: {if (!network.isAllNetworks) "chainId": network.chainId, "query": query}, + queryParameters: {"query": query}, ); _searchTokenLastCancelToken = null; - return (response.data as List).map((token) => TokenDto.fromJson(token)).toList(); + return (singleNetworkResponse.data as List).map((token) { + final singleChainToken = SingleChainTokenDto.fromJson(token); + + return MultiChainTokenDto( + addresses: {network.chainId: singleChainToken.address}, + decimals: {network.chainId: singleChainToken.decimals}, + logoUrl: singleChainToken.logoUrl, + name: singleChainToken.name, + symbol: singleChainToken.symbol, + ); + }).toList(); } Future getTokenPrice(String address, AppNetworks network) async { - final response = await _zupAPIDio.get( - "/tokens/price", - queryParameters: {"address": address, "chainId": network.chainId}, - ); + final response = await _zupAPIDio.get("/tokens/$address/${network.chainId}/price"); return TokenPriceDto.fromJson(response.data); } diff --git a/lib/core/repositories/yield_repository.dart b/lib/core/repositories/yield_repository.dart index 508a705..2f89c1b 100644 --- a/lib/core/repositories/yield_repository.dart +++ b/lib/core/repositories/yield_repository.dart @@ -1,7 +1,7 @@ import 'package:dio/dio.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pools_search_result_dto.dart'; import 'package:zup_app/core/dtos/pool_search_settings_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; -import 'package:zup_app/core/dtos/yields_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; class YieldRepository { @@ -9,7 +9,7 @@ class YieldRepository { final Dio _zupAPIDio; - Future getSingleNetworkYield({ + Future getSingleNetworkYield({ required String? token0Address, required String? token1Address, required String? group0Id, @@ -27,18 +27,14 @@ class YieldRepository { if (group1Id != null) "group1Id": group1Id, }, data: { - "filters": { - "minTvlUsd": searchSettings.minLiquidityUSD, - "blockedProtocols": blockedProtocolIds, - "allowedPoolTypes": [if (searchSettings.allowV3Search) "V3", if (searchSettings.allowV4Search) "V4"], - }, + "filters": {"minimumTvlUsd": searchSettings.minLiquidityUSD, "blockedProtocols": blockedProtocolIds}, }, ); - return YieldsDto.fromJson(response.data); + return LiquidityPoolsSearchResultDto.fromJson(response.data); } - Future getAllNetworksYield({ + Future getAllNetworksYield({ required String? token0InternalId, required String? token1InternalId, required String? group0Id, @@ -56,19 +52,15 @@ class YieldRepository { if (group1Id != null) "group1Id": group1Id, }, data: { - "filters": { - "minTvlUsd": searchSettings.minLiquidityUSD, - "testnetMode": testnetMode, - "blockedProtocols": blockedProtocolIds, - "allowedPoolTypes": [if (searchSettings.allowV3Search) "V3", if (searchSettings.allowV4Search) "V4"], - }, + "filters": {"minimumTvlUsd": searchSettings.minLiquidityUSD, "blockedProtocols": blockedProtocolIds}, + "config": {"testnetMode": testnetMode}, }, ); - return YieldsDto.fromJson(response.data); + return LiquidityPoolsSearchResultDto.fromJson(response.data); } - Future getPoolInfo({ + Future getPoolInfo({ required String poolAddress, required AppNetworks poolNetwork, bool parseWrappedToNative = true, @@ -78,6 +70,6 @@ class YieldRepository { queryParameters: {"parseWrappedToNative": parseWrappedToNative}, ); - return YieldDto.fromJson(response.data); + return LiquidityPoolDto.fromJson(response.data); } } diff --git a/lib/core/zup_analytics.dart b/lib/core/zup_analytics.dart index 2d56766..269b9b8 100644 --- a/lib/core/zup_analytics.dart +++ b/lib/core/zup_analytics.dart @@ -1,6 +1,6 @@ import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:flutter/material.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; import 'package:zup_app/core/repositories/tokens_repository.dart'; class ZupAnalytics { @@ -11,12 +11,7 @@ class ZupAnalytics { Future _log(String name, Map? parameters) async { try { - await firebaseAnalytics.logEvent( - name: name, - parameters: { - ...?parameters, - }, - ); + await firebaseAnalytics.logEvent(name: name, parameters: {...?parameters}); debugPrint("ZupAnalytics: Event $name logged with parameters $parameters"); } catch (e, stacktraces) { @@ -27,41 +22,32 @@ class ZupAnalytics { } Future logDeposit({ - required YieldDto depositedYield, + required LiquidityPoolDto depositedYield, required num amount0Formatted, required num amount1Formatted, required String walletAddress, }) async { try { final tokensPrice = await Future.wait([ - tokensRepository.getTokenPrice( - depositedYield.token0.addresses[depositedYield.network.chainId]!, - depositedYield.network, - ), - tokensRepository.getTokenPrice( - depositedYield.token1.addresses[depositedYield.network.chainId]!, - depositedYield.network, - ) + tokensRepository.getTokenPrice(depositedYield.token0.address, depositedYield.network), + tokensRepository.getTokenPrice(depositedYield.token1.address, depositedYield.network), ]); final amount0UsdDeposited = amount0Formatted * tokensPrice[0].usdPrice; final amount1UsdDeposited = amount1Formatted * tokensPrice[1].usdPrice; final usdAmountDeposited = amount0UsdDeposited + amount1UsdDeposited; - await _log( - "user_deposited", - { - "token0_address": "hex:${depositedYield.token0.addresses[depositedYield.network.chainId]!}", - "token1_address": "hex:${depositedYield.token1.addresses[depositedYield.network.chainId]!}", - "amount0": amount0Formatted, - "amount1": amount1Formatted, - "amount_usd": usdAmountDeposited, - "network": depositedYield.network.label, - "wallet_address": "hex:$walletAddress", - "pool_address": "hex:${depositedYield.poolAddress}", - "protocol_name": depositedYield.protocol.name, - }, - ); + await _log("user_deposited", { + "token0_address": "hex:${depositedYield.token0.address}", + "token1_address": "hex:${depositedYield.token1.address}", + "amount0": amount0Formatted, + "amount1": amount1Formatted, + "amount_usd": usdAmountDeposited, + "network": depositedYield.network.label, + "wallet_address": "hex:$walletAddress", + "pool_address": "hex:${depositedYield.poolAddress}", + "protocol_name": depositedYield.protocol.name, + }); } catch (e) { // ignore } @@ -74,15 +60,12 @@ class ZupAnalytics { required String? group1, required String network, }) async { - await _log( - "user_searched_yields", - { - "token0": "id:$token0", - "token1": "id:$token1", - "group0": "id:$group0", - "group1": "id:$group1", - "network": network, - }, - ); + await _log("user_searched_yields", { + "token0": "id:$token0", + "token1": "id:$token1", + "group0": "id:$group0", + "group1": "id:$group1", + "network": network, + }); } } diff --git a/lib/core/zup_navigator.dart b/lib/core/zup_navigator.dart index 5750bfc..b46b687 100644 --- a/lib/core/zup_navigator.dart +++ b/lib/core/zup_navigator.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:routefly/routefly.dart'; import 'package:zup_app/core/dtos/deposit_page_arguments_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; import 'package:zup_app/core/enums/zup_navigator_paths.dart'; import 'package:zup_app/core/zup_route_params_names.dart'; @@ -50,8 +50,8 @@ class ZupNavigator { Future navigateToInitial() async => await Routefly.navigate(ZupNavigatorPaths.initial.path); Future navigateToDeposit({ - required YieldDto yieldPool, - required YieldTimeFrame selectedTimeframe, + required LiquidityPoolDto yieldPool, + required PoolDataTimeframe selectedTimeframe, required bool parseWrappedToNative, }) async { final depositPathParamNames = ZupNavigatorPaths.deposit.routeParamsNames(); diff --git a/lib/l10n/en.arb b/lib/l10n/en.arb index 21b217c..83872bf 100644 --- a/lib/l10n/en.arb +++ b/lib/l10n/en.arb @@ -27,18 +27,14 @@ "createPageShowMeTheMoney": "Show me the money!", "createPageTitle": "New Position", "dark": "Dark", - "depositPageLoadingTitle": "Getting the pool ready for you...", - "@depositPageLoadingTitle": { - "description": "Used by the deposit page as title for the loading state, before the pool is ready for the user to deposit" + "depositPageBackToNewPositionButtonTitle": "Search other pools", + "@depositPageBackToNewPositionButtonTitle": { + "description": "Used by the deposit page as title for the back button to navigate back to the new position page, if the previous page isn't to select a yield, like paste the url to deposit directly" }, "depositPageBackToYieldsButtonTitle": "Select Yield", "@depositPageBackToYieldsButtonTitle": { "description": "Used by the deposit page as title for the back button to navigate back to the yields page, if the previous page was to select a yield" }, - "depositPageBackToNewPositionButtonTitle": "Search other pools", - "@depositPageBackToNewPositionButtonTitle": { - "description": "Used by the deposit page as title for the back button to navigate back to the new position page, if the previous page isn't to select a yield, like paste the url to deposit directly" - }, "depositPageBestYieldsIn": "Best Yields in", "depositPageDeposit": "Deposit", "depositPageDepositSectionTitle": "Deposit", @@ -95,6 +91,10 @@ "depositPageLoadingStep3Title": "Yield optimizer at work…", "depositPageLoadingStep4Description": "Hang tight, we're filtering and organizing the best pools for you", "depositPageLoadingStep4Title": "Organizing the best pools for you…", + "depositPageLoadingTitle": "Getting the pool ready for you...", + "@depositPageLoadingTitle": { + "description": "Used by the deposit page as title for the loading state, before the pool is ready for the user to deposit" + }, "depositPageMaxRangeOutOfRangeWarningText": "You will not earn fees until the market price move down into your range", "depositPageMinLiquiditySearchAlert": "You’ve set the search to only show pools with more than {minLiquidity}.", "@depositPageMinLiquiditySearchAlert": { @@ -191,6 +191,243 @@ "monthCompact": "30d", "newPosition": "New Position", "noResultsFor": "No results for", + "poolInfoModalAboutPageCopyHook": "Copy Hook Address", + "@poolInfoModalAboutPageCopyHook": { + "description": "Used by the pool info modal to copy the pool hook address if any", + "type": "text" + }, + "poolInfoModalAboutPageCopyToken": "Copy Token Address", + "@poolInfoModalAboutPageCopyToken": { + "description": "Used by the pool info modal to copy one of the pool tokens address", + "type": "text" + }, + "poolInfoModalAboutPageFee": "Fee", + "@poolInfoModalAboutPageFee": { + "description": "Used by the pool info modal as a title for the fee tier field in the about page" + }, + "poolInfoModalAboutPageFeeDescription": "This pool takes {isDynamicFee, select, true {a dynamic} other {{formattedFee}}} fee on each trade and distributes it to the liquidity providers", + "@poolInfoModalAboutPageFeeDescription": { + "placeholders": { + "isDynamicFee": { + "type": "String" + }, + "formattedFee": { + "type": "String" + } + } + }, + "poolInfoModalAboutPageHookCopied": "Copied!", + "@poolInfoModalAboutPageHookCopied": { + "description": "Used by the pool info modal to notify the user that the pool hook address was copied", + "type": "text" + }, + "poolInfoModalAboutPageHooks": "Hooks", + "@poolInfoModalAboutPageHooks": { + "description": "Used by the pool info modal as a title for the hooks field in the about page" + }, + "poolInfoModalAboutPageHooksDescription": "Some pools can include hooks, which are small smart contracts attached to the pool that allow pools to add extra features or rules when people trade or add liquidity", + "@poolInfoModalAboutPageHooksDescription": { + "description": "Used by the pool info modal as a description for the hooks field in the about page to explain what hooks are to the user" + }, + "poolInfoModalAboutPageHooksNo": "No", + "@poolInfoModalAboutPageHooksNo": { + "description": "Used by the pool info modal as a value for the hooks field in the about page when there are no hooks in the pool" + }, + "poolInfoModalAboutPageNetwork": "Network", + "@poolInfoModalAboutPageNetwork": { + "description": "Used by the pool info modal as a title for the section that has information about the pool's blockchain, in the about page", + "type": "text" + }, + "poolInfoModalAboutPagePoolTypeValue": "{poolType} Pool", + "@poolInfoModalAboutPagePoolTypeValue": { + "description": "Used by the pool info modal as a value for the pool type field in the about page", + "placeholders": { + "poolType": { + "type": "String" + } + } + }, + "poolInfoModalAboutPageProtocol": "Protocol", + "@poolInfoModalAboutPageProtocol": { + "description": "Used by the pool info modal as a title for the section that has information about the pool's protocol, in the about page", + "type": "text" + }, + "poolInfoModalAboutPageTimeCreatedAgo": "Created {timeAgo}", + "@poolInfoModalAboutPageTimeCreatedAgo": { + "description": "Used by the pool info modal in the about page to show how long ago a pool was created", + "placeholders": { + "timeAgo": { + "description": "The time ago for the pool creation, in a human readable format like 1 day ago", + "type": "String" + } + } + }, + "poolInfoModalAboutPageTokenCopied": "Copied!", + "@poolInfoModalAboutPageTokenCopied": { + "description": "Used by the pool info modal to notify the user that one of the pool tokens address was copied", + "type": "text" + }, + "poolInfoModalAboutPageTokens": "Tokens", + "@poolInfoModalAboutPageTokens": { + "description": "Used by the pool info modal as a title for the tokens section of the about page. This section lists the tokens in the pool", + "type": "text" + }, + "poolInfoModalAboutPageType": "Type", + "@poolInfoModalAboutPageType": { + "description": "Used by the pool info modal as a title for the pool type field in the about page" + }, + "poolInfoModalAboutPoolTabTitle": "About Pool", + "@poolInfoModalAboutPoolTabTitle": { + "description": "Used by the pool info modal to title the about pool tab at a tab bar", + "type": "text" + }, + "poolInfoModalAddLiquidity": "Add Liquidity", + "@poolInfoModalAddLiquidity": { + "description": "Used by the pool info modal to proceed to the add liquidity page with the current pool", + "type": "text" + }, + "poolInfoModalBottomSheetTitle": "Pool Information", + "@poolInfoModalBottomSheetTitle": { + "description": "Used by the pool info modal as title for the bottom sheet that displays pool information" + }, + "poolInfoModalCopied": "Copied!", + "@poolInfoModalCopied": { + "description": "Used by the pool info modal to notify the user that the pool address was copied", + "type": "text" + }, + "poolInfoModalCopyPoolAddress": "Copy Pool Address", + "@poolInfoModalCopyPoolAddress": { + "description": "Used by the pool info modal to copy the current pool address", + "type": "text" + }, + "poolInfoModalPoolStatsTabTitle": "Pool Stats", + "@poolInfoModalPoolStatsTabTitle": { + "description": "Used by the pool info modal to title the pool stats tab at a tab bar", + "type": "text" + }, + "poolInfoModalStatePageSwapVolumeDescription": "{formattedVolume} in trades happened in the last {timeframeLabel} at this pool", + "@poolInfoModalStatePageSwapVolumeDescription": { + "description": "Used by the pool info modal to explain what's the swap volume of a pool to the user in the state page", + "placeholders": { + "formattedVolume": { + "description": "The formatted volume in USD for the passed timeframe", + "type": "String" + }, + "timeframeLabel": { + "description": "The timeframe used for the swap volume calculation", + "type": "String" + } + } + }, + "poolInfoModalStatsPageFees": "{timeframeLabel} Fees", + "@poolInfoModalStatsPageFees": { + "description": "Used by the pool info modal as a title for the fees field in the passed timeframe in the stats page", + "placeholders": { + "timeframeLabel": { + "description": "The timeframe used for the fees calculation", + "type": "String" + } + } + }, + "poolInfoModalStatsPageFeesDescription": "This pool has distributed {formattedFees} of fees in ${timeframeLabel} to liquidity providers", + "@poolInfoModalStatsPageFeesDescription": { + "description": "Used by the pool info modal to explain what's the fees of a pool to the user in the stats page", + "placeholders": { + "formattedFees": { + "description": "The formatted fees in USD for the passed timeframe", + "type": "String" + }, + "timeframeLabel": { + "description": "The timeframe used for the fees calculation", + "type": "String" + } + } + }, + "poolInfoModalStatsPageNetInflow": "{timeframeLabel} Net Inflow", + "@poolInfoModalStatsPageNetInflow": { + "description": "Used by the pool info modal as a title for the net inflow of liquidity in the passed timeframe in the stats page", + "placeholders": { + "timeframeLabel": { + "description": "The timeframe used for the net inflow calculation", + "type": "String" + } + } + }, + "poolInfoModalStatsPageNetInflowDescription": "This pool’s TVL changed by {formattedNetInflow} over the last {timeframeLabel} from liquidity provider deposits and withdrawals. It may differ from the current TVL due to price movements", + "@poolInfoModalStatsPageNetInflowDescription": { + "description": "Used by the pool info modal to explain what's the net inflow of a pool to the user in the state page", + "placeholders": { + "formattedNetInflow": { + "description": "The pool's net inflow formatted as USD", + "type": "String" + }, + "timeframeLabel": { + "description": "The timeframe used for the net inflow calculation", + "type": "String" + } + } + }, + "poolInfoModalStatsPageSwapVolume": "{timeframeLabel} Swap Volume", + "@poolInfoModalStatsPageSwapVolume": { + "description": "Used by the pool info modal as a title for the swap volume field in the passed timeframe in the stats page", + "placeholders": { + "timeframeLabel": { + "description": "The timeframe used for the swap volume calculation", + "type": "String" + } + } + }, + "poolInfoModalStatsPageTimeframeTitle": "Stats Timeframe", + "@poolInfoModalStatsPageTimeframeTitle": { + "description": "Used by the pool info modal in the stats page to title the timeframe selector to change the stats time frame, like to 24h, 7d, 30d, etc...", + "type": "text" + }, + "poolInfoModalStatsPageTvlDescription": "This pool has {formattedTvl} deposited in it, based on the current price of the tokens in the pool.", + "@poolInfoModalStatsPageTvlDescription": { + "description": "Used by the pool info modal to explain what's the TVL of a pool to the user in the stats page", + "placeholders": { + "formattedTvl": { + "description": "The TVL formatted as USD for the pool", + "type": "String" + } + } + }, + "poolInfoModalStatsPageYearlyYield": "{timeframeLabel} Yearly Yield", + "@poolInfoModalStatsPageYearlyYield": { + "description": "Used by the pool info modal as a title for the yearly yield field in the passed timeframe in the stats page", + "placeholders": { + "timeframeLabel": { + "description": "The timeframe used for the yearly yield calculation", + "type": "String" + } + } + }, + "poolInfoModalStatsPageYearlyYieldDescription": "This pool has an estimated yearly yield of {yearlyYieldFormatted} based on {timeframeLabel} of data from fees distributed to liquidity providers", + "@poolInfoModalStatsPageYearlyYieldDescription": { + "description": "Used by the pool info modal to explain what's the yearly yield of a pool to the user in the stats page", + "placeholders": { + "yearlyYieldFormatted": { + "description": "The yearly yield formatted as a percentage", + "type": "String" + }, + "timeframeLabel": { + "description": "The timeframe used for the yearly yield calculation", + "type": "String" + } + } + }, + "poolTokensButtonViewAtDexcreener": "View this pool at DEX Screener", + "@poolTokensButtonViewAtDexcreener": { + "description": "A tooltip message used by the pool tokens button to explain what clicking on the button does" + }, + "poolTypeV3Description": "This pool uses the Uniswap V3 model, which allows more efficient trading and customizable liquidity ranges", + "@poolTypeV3Description": { + "description": "Used as tooltip message to explain what's a V3 pool to the user" + }, + "poolTypeV4Description": "This pool uses the Uniswap V4 model, which introduces hooks and a more flexible architecture for custom pool logic", + "@poolTypeV4Description": { + "description": "Used as tooltip message to explain what's a V4 pool to the user" + }, "popularTokens": "Popular Tokens", "positionCardLiquidity": "Liquidity: ", "positionCardMax": "Max: ", @@ -366,6 +603,10 @@ "tokenSelectorModalTokenGroups": "Token Groups", "tokenSelectorModalTokenGroupsTooltipMessage": "Token groups let you search pools using multiple tokens in one go. Think of them like batch queries, want all USD stablecoins? Pick the group and we'll surface every relevant pool. You can also match groups against single tokens or other groups to discover deep liquidity.", "tvl": "TVL", + "@tvl": { + "description": "Used anywhere that wants to show the total value locked of something", + "type": "text" + }, "twentyFourHours": "24h", "twentyFourHoursCompact": "24h", "understood": "Understood", @@ -373,6 +614,84 @@ "week": "Week", "weekCompact": "7d", "whatsThisQuestionText": "What's this?", + "xDaysAndHoursAgo": "{days, plural, one{{days} day} other{{days} days}}{hours, plural, zero{} one{ and {hours} hour} other{ and {hours} hours}} ago", + "@xDaysAndHoursAgo": { + "description": "Used anywhere that implements days ago time, to describe how many days ago something happened", + "placeholders": { + "days": { + "type": "int" + }, + "hours": { + "type": "int" + } + } + }, + "xHoursAndMinutesAgo": "{hours, plural, one{{hours} hour} other{{hours} hours}}{minutes, plural, zero{} one{ and {minutes} minute} other{ and {minutes} minutes}} ago", + "@xHoursAndMinutesAgo": { + "description": "Used anywhere that implements hours ago time, to describe how many hours ago something happened", + "placeholders": { + "hours": { + "type": "int" + }, + "minutes": { + "type": "int" + } + } + }, + "xMillisecondsAgo": "{milliseconds, plural, one{{milliseconds} millisecond} other{{milliseconds} milliseconds}} ago", + "@xMillisecondsAgo": { + "description": "Used anywhere that implements milliseconds ago time, to describe how many milliseconds ago something happened", + "placeholders": { + "milliseconds": { + "type": "int" + } + } + }, + "xMinutesAndSecondsAgo": "{minutes, plural, one{{minutes} minute} other{{minutes} minutes}}{seconds, plural, =0{} other{ and {seconds, plural, one{{seconds} second} other{{seconds} seconds}}}} ago", + "@xMinutesAndSecondsAgo": { + "description": "Used anywhere that implements minutes ago time, to describe how many minutes ago something happened", + "placeholders": { + "minutes": { + "type": "int" + }, + "seconds": { + "type": "int" + } + } + }, + "xMonthsAndDaysAgo": "{months, plural, one{{months} month} other{{months} months}}{days, plural, zero{} one{ and {days} day} other{ and {days} days}} ago", + "@xMonthsAndDaysAgo": { + "description": "Used anywhere that implements months ago time, to describe how many months ago something happened", + "placeholders": { + "months": { + "type": "int" + }, + "days": { + "type": "int" + } + } + }, + "xSecondsAgo": "{seconds, plural, one{{seconds} second} other{{seconds} seconds}} ago", + "@xSecondsAgo": { + "description": "Used anywhere that implements seconds ago time, to describe how many seconds ago something happened", + "placeholders": { + "seconds": { + "type": "int" + } + } + }, + "xYearsAndMonthsAgo": "{years, plural, one{{years} year} other{{years} years}}{months, plural, zero{} one{ and {months} month} other{ and {months} months}} ago", + "@xYearsAndMonthsAgo": { + "description": "Used anywhere that implements years ago time, to describe how many years ago something happened", + "placeholders": { + "years": { + "type": "int" + }, + "months": { + "type": "int" + } + } + }, "yieldCardAverageYieldYearly": "Average Yearly Yield", "yieldCardDeposit": "Deposit", "@yieldCardDeposit": { diff --git a/lib/l10n/gen/app_localizations.dart b/lib/l10n/gen/app_localizations.dart index e8d6fcd..3abd074 100644 --- a/lib/l10n/gen/app_localizations.dart +++ b/lib/l10n/gen/app_localizations.dart @@ -255,11 +255,11 @@ abstract class S { /// **'Dark'** String get dark; - /// Used by the deposit page as title for the loading state, before the pool is ready for the user to deposit + /// Used by the deposit page as title for the back button to navigate back to the new position page, if the previous page isn't to select a yield, like paste the url to deposit directly /// /// In en, this message translates to: - /// **'Getting the pool ready for you...'** - String get depositPageLoadingTitle; + /// **'Search other pools'** + String get depositPageBackToNewPositionButtonTitle; /// Used by the deposit page as title for the back button to navigate back to the yields page, if the previous page was to select a yield /// @@ -267,12 +267,6 @@ abstract class S { /// **'Select Yield'** String get depositPageBackToYieldsButtonTitle; - /// Used by the deposit page as title for the back button to navigate back to the new position page, if the previous page isn't to select a yield, like paste the url to deposit directly - /// - /// In en, this message translates to: - /// **'Search other pools'** - String get depositPageBackToNewPositionButtonTitle; - /// No description provided for @depositPageBestYieldsIn. /// /// In en, this message translates to: @@ -405,6 +399,12 @@ abstract class S { /// **'Organizing the best pools for you…'** String get depositPageLoadingStep4Title; + /// Used by the deposit page as title for the loading state, before the pool is ready for the user to deposit + /// + /// In en, this message translates to: + /// **'Getting the pool ready for you...'** + String get depositPageLoadingTitle; + /// No description provided for @depositPageMaxRangeOutOfRangeWarningText. /// /// In en, this message translates to: @@ -675,6 +675,225 @@ abstract class S { /// **'No results for'** String get noResultsFor; + /// Used by the pool info modal to copy the pool hook address if any + /// + /// In en, this message translates to: + /// **'Copy Hook Address'** + String get poolInfoModalAboutPageCopyHook; + + /// Used by the pool info modal to copy one of the pool tokens address + /// + /// In en, this message translates to: + /// **'Copy Token Address'** + String get poolInfoModalAboutPageCopyToken; + + /// Used by the pool info modal as a title for the fee tier field in the about page + /// + /// In en, this message translates to: + /// **'Fee'** + String get poolInfoModalAboutPageFee; + + /// No description provided for @poolInfoModalAboutPageFeeDescription. + /// + /// In en, this message translates to: + /// **'This pool takes {isDynamicFee, select, true {a dynamic} other {{formattedFee}}} fee on each trade and distributes it to the liquidity providers'** + String poolInfoModalAboutPageFeeDescription({ + required String isDynamicFee, + required String formattedFee, + }); + + /// Used by the pool info modal to notify the user that the pool hook address was copied + /// + /// In en, this message translates to: + /// **'Copied!'** + String get poolInfoModalAboutPageHookCopied; + + /// Used by the pool info modal as a title for the hooks field in the about page + /// + /// In en, this message translates to: + /// **'Hooks'** + String get poolInfoModalAboutPageHooks; + + /// Used by the pool info modal as a description for the hooks field in the about page to explain what hooks are to the user + /// + /// In en, this message translates to: + /// **'Some pools can include hooks, which are small smart contracts attached to the pool that allow pools to add extra features or rules when people trade or add liquidity'** + String get poolInfoModalAboutPageHooksDescription; + + /// Used by the pool info modal as a value for the hooks field in the about page when there are no hooks in the pool + /// + /// In en, this message translates to: + /// **'No'** + String get poolInfoModalAboutPageHooksNo; + + /// Used by the pool info modal as a title for the section that has information about the pool's blockchain, in the about page + /// + /// In en, this message translates to: + /// **'Network'** + String get poolInfoModalAboutPageNetwork; + + /// Used by the pool info modal as a value for the pool type field in the about page + /// + /// In en, this message translates to: + /// **'{poolType} Pool'** + String poolInfoModalAboutPagePoolTypeValue({required String poolType}); + + /// Used by the pool info modal as a title for the section that has information about the pool's protocol, in the about page + /// + /// In en, this message translates to: + /// **'Protocol'** + String get poolInfoModalAboutPageProtocol; + + /// Used by the pool info modal in the about page to show how long ago a pool was created + /// + /// In en, this message translates to: + /// **'Created {timeAgo}'** + String poolInfoModalAboutPageTimeCreatedAgo({required String timeAgo}); + + /// Used by the pool info modal to notify the user that one of the pool tokens address was copied + /// + /// In en, this message translates to: + /// **'Copied!'** + String get poolInfoModalAboutPageTokenCopied; + + /// Used by the pool info modal as a title for the tokens section of the about page. This section lists the tokens in the pool + /// + /// In en, this message translates to: + /// **'Tokens'** + String get poolInfoModalAboutPageTokens; + + /// Used by the pool info modal as a title for the pool type field in the about page + /// + /// In en, this message translates to: + /// **'Type'** + String get poolInfoModalAboutPageType; + + /// Used by the pool info modal to title the about pool tab at a tab bar + /// + /// In en, this message translates to: + /// **'About Pool'** + String get poolInfoModalAboutPoolTabTitle; + + /// Used by the pool info modal to proceed to the add liquidity page with the current pool + /// + /// In en, this message translates to: + /// **'Add Liquidity'** + String get poolInfoModalAddLiquidity; + + /// Used by the pool info modal as title for the bottom sheet that displays pool information + /// + /// In en, this message translates to: + /// **'Pool Information'** + String get poolInfoModalBottomSheetTitle; + + /// Used by the pool info modal to notify the user that the pool address was copied + /// + /// In en, this message translates to: + /// **'Copied!'** + String get poolInfoModalCopied; + + /// Used by the pool info modal to copy the current pool address + /// + /// In en, this message translates to: + /// **'Copy Pool Address'** + String get poolInfoModalCopyPoolAddress; + + /// Used by the pool info modal to title the pool stats tab at a tab bar + /// + /// In en, this message translates to: + /// **'Pool Stats'** + String get poolInfoModalPoolStatsTabTitle; + + /// Used by the pool info modal to explain what's the swap volume of a pool to the user in the state page + /// + /// In en, this message translates to: + /// **'{formattedVolume} in trades happened in the last {timeframeLabel} at this pool'** + String poolInfoModalStatePageSwapVolumeDescription({ + required String formattedVolume, + required String timeframeLabel, + }); + + /// Used by the pool info modal as a title for the fees field in the passed timeframe in the stats page + /// + /// In en, this message translates to: + /// **'{timeframeLabel} Fees'** + String poolInfoModalStatsPageFees({required String timeframeLabel}); + + /// Used by the pool info modal to explain what's the fees of a pool to the user in the stats page + /// + /// In en, this message translates to: + /// **'This pool has distributed {formattedFees} of fees in \${timeframeLabel} to liquidity providers'** + String poolInfoModalStatsPageFeesDescription({ + required String formattedFees, + required String timeframeLabel, + }); + + /// Used by the pool info modal as a title for the net inflow of liquidity in the passed timeframe in the stats page + /// + /// In en, this message translates to: + /// **'{timeframeLabel} Net Inflow'** + String poolInfoModalStatsPageNetInflow({required String timeframeLabel}); + + /// Used by the pool info modal to explain what's the net inflow of a pool to the user in the state page + /// + /// In en, this message translates to: + /// **'This pool’s TVL changed by {formattedNetInflow} over the last {timeframeLabel} from liquidity provider deposits and withdrawals. It may differ from the current TVL due to price movements'** + String poolInfoModalStatsPageNetInflowDescription({ + required String formattedNetInflow, + required String timeframeLabel, + }); + + /// Used by the pool info modal as a title for the swap volume field in the passed timeframe in the stats page + /// + /// In en, this message translates to: + /// **'{timeframeLabel} Swap Volume'** + String poolInfoModalStatsPageSwapVolume({required String timeframeLabel}); + + /// Used by the pool info modal in the stats page to title the timeframe selector to change the stats time frame, like to 24h, 7d, 30d, etc... + /// + /// In en, this message translates to: + /// **'Stats Timeframe'** + String get poolInfoModalStatsPageTimeframeTitle; + + /// Used by the pool info modal to explain what's the TVL of a pool to the user in the stats page + /// + /// In en, this message translates to: + /// **'This pool has {formattedTvl} deposited in it, based on the current price of the tokens in the pool.'** + String poolInfoModalStatsPageTvlDescription({required String formattedTvl}); + + /// Used by the pool info modal as a title for the yearly yield field in the passed timeframe in the stats page + /// + /// In en, this message translates to: + /// **'{timeframeLabel} Yearly Yield'** + String poolInfoModalStatsPageYearlyYield({required String timeframeLabel}); + + /// Used by the pool info modal to explain what's the yearly yield of a pool to the user in the stats page + /// + /// In en, this message translates to: + /// **'This pool has an estimated yearly yield of {yearlyYieldFormatted} based on {timeframeLabel} of data from fees distributed to liquidity providers'** + String poolInfoModalStatsPageYearlyYieldDescription({ + required String yearlyYieldFormatted, + required String timeframeLabel, + }); + + /// A tooltip message used by the pool tokens button to explain what clicking on the button does + /// + /// In en, this message translates to: + /// **'View this pool at DEX Screener'** + String get poolTokensButtonViewAtDexcreener; + + /// Used as tooltip message to explain what's a V3 pool to the user + /// + /// In en, this message translates to: + /// **'This pool uses the Uniswap V3 model, which allows more efficient trading and customizable liquidity ranges'** + String get poolTypeV3Description; + + /// Used as tooltip message to explain what's a V4 pool to the user + /// + /// In en, this message translates to: + /// **'This pool uses the Uniswap V4 model, which introduces hooks and a more flexible architecture for custom pool logic'** + String get poolTypeV4Description; + /// No description provided for @popularTokens. /// /// In en, this message translates to: @@ -1117,7 +1336,7 @@ abstract class S { /// **'Token groups let you search pools using multiple tokens in one go. Think of them like batch queries, want all USD stablecoins? Pick the group and we\'ll surface every relevant pool. You can also match groups against single tokens or other groups to discover deep liquidity.'** String get tokenSelectorModalTokenGroupsTooltipMessage; - /// No description provided for @tvl. + /// Used anywhere that wants to show the total value locked of something /// /// In en, this message translates to: /// **'TVL'** @@ -1165,6 +1384,48 @@ abstract class S { /// **'What\'s this?'** String get whatsThisQuestionText; + /// Used anywhere that implements days ago time, to describe how many days ago something happened + /// + /// In en, this message translates to: + /// **'{days, plural, one{{days} day} other{{days} days}}{hours, plural, zero{} one{ and {hours} hour} other{ and {hours} hours}} ago'** + String xDaysAndHoursAgo({required int days, required int hours}); + + /// Used anywhere that implements hours ago time, to describe how many hours ago something happened + /// + /// In en, this message translates to: + /// **'{hours, plural, one{{hours} hour} other{{hours} hours}}{minutes, plural, zero{} one{ and {minutes} minute} other{ and {minutes} minutes}} ago'** + String xHoursAndMinutesAgo({required int hours, required int minutes}); + + /// Used anywhere that implements milliseconds ago time, to describe how many milliseconds ago something happened + /// + /// In en, this message translates to: + /// **'{milliseconds, plural, one{{milliseconds} millisecond} other{{milliseconds} milliseconds}} ago'** + String xMillisecondsAgo({required int milliseconds}); + + /// Used anywhere that implements minutes ago time, to describe how many minutes ago something happened + /// + /// In en, this message translates to: + /// **'{minutes, plural, one{{minutes} minute} other{{minutes} minutes}}{seconds, plural, =0{} other{ and {seconds, plural, one{{seconds} second} other{{seconds} seconds}}}} ago'** + String xMinutesAndSecondsAgo({required int minutes, required int seconds}); + + /// Used anywhere that implements months ago time, to describe how many months ago something happened + /// + /// In en, this message translates to: + /// **'{months, plural, one{{months} month} other{{months} months}}{days, plural, zero{} one{ and {days} day} other{ and {days} days}} ago'** + String xMonthsAndDaysAgo({required int months, required int days}); + + /// Used anywhere that implements seconds ago time, to describe how many seconds ago something happened + /// + /// In en, this message translates to: + /// **'{seconds, plural, one{{seconds} second} other{{seconds} seconds}} ago'** + String xSecondsAgo({required int seconds}); + + /// Used anywhere that implements years ago time, to describe how many years ago something happened + /// + /// In en, this message translates to: + /// **'{years, plural, one{{years} year} other{{years} years}}{months, plural, zero{} one{ and {months} month} other{ and {months} months}} ago'** + String xYearsAndMonthsAgo({required int years, required int months}); + /// No description provided for @yieldCardAverageYieldYearly. /// /// In en, this message translates to: diff --git a/lib/l10n/gen/app_localizations_en.dart b/lib/l10n/gen/app_localizations_en.dart index 675d3cf..014d6b0 100644 --- a/lib/l10n/gen/app_localizations_en.dart +++ b/lib/l10n/gen/app_localizations_en.dart @@ -96,14 +96,11 @@ class SEn extends S { String get dark => 'Dark'; @override - String get depositPageLoadingTitle => 'Getting the pool ready for you...'; + String get depositPageBackToNewPositionButtonTitle => 'Search other pools'; @override String get depositPageBackToYieldsButtonTitle => 'Select Yield'; - @override - String get depositPageBackToNewPositionButtonTitle => 'Search other pools'; - @override String get depositPageBestYieldsIn => 'Best Yields in'; @@ -188,6 +185,9 @@ class SEn extends S { String get depositPageLoadingStep4Title => 'Organizing the best pools for you…'; + @override + String get depositPageLoadingTitle => 'Getting the pool ready for you...'; + @override String get depositPageMaxRangeOutOfRangeWarningText => 'You will not earn fees until the market price move down into your range'; @@ -353,6 +353,155 @@ class SEn extends S { @override String get noResultsFor => 'No results for'; + @override + String get poolInfoModalAboutPageCopyHook => 'Copy Hook Address'; + + @override + String get poolInfoModalAboutPageCopyToken => 'Copy Token Address'; + + @override + String get poolInfoModalAboutPageFee => 'Fee'; + + @override + String poolInfoModalAboutPageFeeDescription({ + required String isDynamicFee, + required String formattedFee, + }) { + String _temp0 = intl.Intl.selectLogic(isDynamicFee, { + 'true': 'a dynamic', + 'other': '$formattedFee', + }); + return 'This pool takes $_temp0 fee on each trade and distributes it to the liquidity providers'; + } + + @override + String get poolInfoModalAboutPageHookCopied => 'Copied!'; + + @override + String get poolInfoModalAboutPageHooks => 'Hooks'; + + @override + String get poolInfoModalAboutPageHooksDescription => + 'Some pools can include hooks, which are small smart contracts attached to the pool that allow pools to add extra features or rules when people trade or add liquidity'; + + @override + String get poolInfoModalAboutPageHooksNo => 'No'; + + @override + String get poolInfoModalAboutPageNetwork => 'Network'; + + @override + String poolInfoModalAboutPagePoolTypeValue({required String poolType}) { + return '$poolType Pool'; + } + + @override + String get poolInfoModalAboutPageProtocol => 'Protocol'; + + @override + String poolInfoModalAboutPageTimeCreatedAgo({required String timeAgo}) { + return 'Created $timeAgo'; + } + + @override + String get poolInfoModalAboutPageTokenCopied => 'Copied!'; + + @override + String get poolInfoModalAboutPageTokens => 'Tokens'; + + @override + String get poolInfoModalAboutPageType => 'Type'; + + @override + String get poolInfoModalAboutPoolTabTitle => 'About Pool'; + + @override + String get poolInfoModalAddLiquidity => 'Add Liquidity'; + + @override + String get poolInfoModalBottomSheetTitle => 'Pool Information'; + + @override + String get poolInfoModalCopied => 'Copied!'; + + @override + String get poolInfoModalCopyPoolAddress => 'Copy Pool Address'; + + @override + String get poolInfoModalPoolStatsTabTitle => 'Pool Stats'; + + @override + String poolInfoModalStatePageSwapVolumeDescription({ + required String formattedVolume, + required String timeframeLabel, + }) { + return '$formattedVolume in trades happened in the last $timeframeLabel at this pool'; + } + + @override + String poolInfoModalStatsPageFees({required String timeframeLabel}) { + return '$timeframeLabel Fees'; + } + + @override + String poolInfoModalStatsPageFeesDescription({ + required String formattedFees, + required String timeframeLabel, + }) { + return 'This pool has distributed $formattedFees of fees in \$$timeframeLabel to liquidity providers'; + } + + @override + String poolInfoModalStatsPageNetInflow({required String timeframeLabel}) { + return '$timeframeLabel Net Inflow'; + } + + @override + String poolInfoModalStatsPageNetInflowDescription({ + required String formattedNetInflow, + required String timeframeLabel, + }) { + return 'This pool’s TVL changed by $formattedNetInflow over the last $timeframeLabel from liquidity provider deposits and withdrawals. It may differ from the current TVL due to price movements'; + } + + @override + String poolInfoModalStatsPageSwapVolume({required String timeframeLabel}) { + return '$timeframeLabel Swap Volume'; + } + + @override + String get poolInfoModalStatsPageTimeframeTitle => 'Stats Timeframe'; + + @override + String poolInfoModalStatsPageTvlDescription({required String formattedTvl}) { + return 'This pool has $formattedTvl deposited in it, based on the current price of the tokens in the pool.'; + } + + @override + String poolInfoModalStatsPageYearlyYield({required String timeframeLabel}) { + return '$timeframeLabel Yearly Yield'; + } + + @override + String poolInfoModalStatsPageYearlyYieldDescription({ + required String yearlyYieldFormatted, + required String timeframeLabel, + }) { + return 'This pool has an estimated yearly yield of $yearlyYieldFormatted based on $timeframeLabel of data from fees distributed to liquidity providers'; + } + + @override + String get poolTokensButtonViewAtDexcreener => + 'View this pool at DEX Screener'; + + @override + String get poolTypeV3Description => + 'This pool uses the Uniswap V3 model, which allows more efficient trading and customizable liquidity ranges'; + + @override + String get poolTypeV4Description => + 'This pool uses the Uniswap V4 model, which introduces hooks and a more flexible architecture for custom pool logic'; + @override String get popularTokens => 'Popular Tokens'; @@ -657,6 +806,123 @@ class SEn extends S { @override String get whatsThisQuestionText => 'What\'s this?'; + @override + String xDaysAndHoursAgo({required int days, required int hours}) { + String _temp0 = intl.Intl.pluralLogic( + days, + locale: localeName, + other: '$days days', + one: '$days day', + ); + String _temp1 = intl.Intl.pluralLogic( + hours, + locale: localeName, + other: ' and $hours hours', + one: ' and $hours hour', + zero: '', + ); + return '$_temp0$_temp1 ago'; + } + + @override + String xHoursAndMinutesAgo({required int hours, required int minutes}) { + String _temp0 = intl.Intl.pluralLogic( + hours, + locale: localeName, + other: '$hours hours', + one: '$hours hour', + ); + String _temp1 = intl.Intl.pluralLogic( + minutes, + locale: localeName, + other: ' and $minutes minutes', + one: ' and $minutes minute', + zero: '', + ); + return '$_temp0$_temp1 ago'; + } + + @override + String xMillisecondsAgo({required int milliseconds}) { + String _temp0 = intl.Intl.pluralLogic( + milliseconds, + locale: localeName, + other: '$milliseconds milliseconds', + one: '$milliseconds millisecond', + ); + return '$_temp0 ago'; + } + + @override + String xMinutesAndSecondsAgo({required int minutes, required int seconds}) { + String _temp0 = intl.Intl.pluralLogic( + minutes, + locale: localeName, + other: '$minutes minutes', + one: '$minutes minute', + ); + String _temp1 = intl.Intl.pluralLogic( + seconds, + locale: localeName, + other: '$seconds seconds', + one: '$seconds second', + ); + String _temp2 = intl.Intl.pluralLogic( + seconds, + locale: localeName, + other: ' and $_temp1', + zero: '', + ); + return '$_temp0$_temp2 ago'; + } + + @override + String xMonthsAndDaysAgo({required int months, required int days}) { + String _temp0 = intl.Intl.pluralLogic( + months, + locale: localeName, + other: '$months months', + one: '$months month', + ); + String _temp1 = intl.Intl.pluralLogic( + days, + locale: localeName, + other: ' and $days days', + one: ' and $days day', + zero: '', + ); + return '$_temp0$_temp1 ago'; + } + + @override + String xSecondsAgo({required int seconds}) { + String _temp0 = intl.Intl.pluralLogic( + seconds, + locale: localeName, + other: '$seconds seconds', + one: '$seconds second', + ); + return '$_temp0 ago'; + } + + @override + String xYearsAndMonthsAgo({required int years, required int months}) { + String _temp0 = intl.Intl.pluralLogic( + years, + locale: localeName, + other: '$years years', + one: '$years year', + ); + String _temp1 = intl.Intl.pluralLogic( + months, + locale: localeName, + other: ' and $months months', + one: ' and $months month', + zero: '', + ); + return '$_temp0$_temp1 ago'; + } + @override String get yieldCardAverageYieldYearly => 'Average Yearly Yield'; diff --git a/lib/widgets/app_header/app_header.dart b/lib/widgets/app_header/app_header.dart index 3942ebc..5cf201a 100644 --- a/lib/widgets/app_header/app_header.dart +++ b/lib/widgets/app_header/app_header.dart @@ -144,9 +144,16 @@ class _AppHeaderState extends State with DeviceInfoMixin { ConnectButton(compact: isMobileSize(context)), const SizedBox(width: 12), ZupIconButton( - iconColor: context.brightness.isLight ? ZupColors.brand : ZupColors.white, - - icon: Transform.rotate(angle: pi / 2, child: Assets.icons.ellipsis.svg(height: 3.5)), + icon: Transform.rotate( + angle: pi / 2, + child: Assets.icons.ellipsis.svg( + height: 3.5, + colorFilter: ColorFilter.mode( + context.brightness.isLight ? ZupColors.brand : ZupColors.white, + BlendMode.srcIn, + ), + ), + ), onPressed: (context) { AppSettingsDropdown.show(context); }, diff --git a/lib/widgets/pool_info_modal/pages/about_page.dart b/lib/widgets/pool_info_modal/pages/about_page.dart new file mode 100644 index 0000000..2b748af --- /dev/null +++ b/lib/widgets/pool_info_modal/pages/about_page.dart @@ -0,0 +1,276 @@ +part of '../pool_info_modal.dart'; + +class _AboutPage extends StatefulWidget { + const _AboutPage(this.liquidityPool); + + final LiquidityPoolDto liquidityPool; + + @override + State<_AboutPage> createState() => _AboutPageState(); +} + +class _AboutPageState extends State<_AboutPage> with DeviceInfoMixin { + final zupNetworkImage = inject(); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + Wrap( + runSpacing: 10, + children: [ + ZupTooltip.text( + message: isMobileDevice + ? S + .of(context) + .poolInfoModalAboutPageFeeDescription( + isDynamicFee: widget.liquidityPool.isDynamicFee.toString(), + formattedFee: widget.liquidityPool.currentFeeTierFormatted, + ) + : "", + child: ZupTitledValueTag( + value: widget.liquidityPool.isDynamicFee ? "Dynamic" : widget.liquidityPool.currentFeeTierFormatted, + title: S.of(context).poolInfoModalAboutPageFee, + trailingIcon: ZupTooltip.text( + key: const Key("fee-tooltip"), + message: S + .of(context) + .poolInfoModalAboutPageFeeDescription( + isDynamicFee: widget.liquidityPool.isDynamicFee.toString(), + formattedFee: widget.liquidityPool.currentFeeTierFormatted, + ), + constraints: const BoxConstraints(maxWidth: 200), + child: Assets.icons.infoCircle.svg( + height: 15, + width: 15, + colorFilter: const ColorFilter.mode(ZupColors.gray, BlendMode.srcIn), + ), + ), + ), + ), + const SizedBox(width: 10), + ZupTooltip.text( + message: isMobileDevice ? widget.liquidityPool.poolType.description(context) : "", + child: ZupTitledValueTag( + title: S.of(context).poolInfoModalAboutPageType, + value: S.of(context).poolInfoModalAboutPagePoolTypeValue(poolType: widget.liquidityPool.poolType.label), + trailingIcon: ZupTooltip.text( + key: const Key("pool-type-tooltip"), + message: widget.liquidityPool.poolType.description(context), + constraints: const BoxConstraints(maxWidth: 200), + child: Assets.icons.infoCircle.svg( + height: 15, + width: 15, + colorFilter: const ColorFilter.mode(ZupColors.gray, BlendMode.srcIn), + ), + ), + ), + ), + if (widget.liquidityPool.poolType.isV4) ...[ + const SizedBox(width: 10), + ZupTooltip.text( + message: isMobileDevice ? S.of(context).poolInfoModalAboutPageHooksDescription : "", + child: ZupTitledValueTag( + title: S.of(context).poolInfoModalAboutPageHooks, + value: + widget.liquidityPool.hook?.address.shortAddress(prefixAndSuffixLength: 4) ?? + S.of(context).poolInfoModalAboutPageHooksNo, + trailingIcon: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.liquidityPool.hook != null) ...[ + ZupSwitchingIconButton( + key: const Key("copy-hook-button"), + restIconTooltipMessage: S.of(context).poolInfoModalAboutPageCopyHook, + pressedIconTooltipMessage: S.of(context).poolInfoModalAboutPageHookCopied, + padding: const EdgeInsets.all(2), + backgroundColor: Colors.transparent, + restIcon: Assets.icons.documentOnDocument.svg( + height: 15, + width: 15, + colorFilter: ColorFilter.mode( + ZupThemeColors.backgroundInverse.themed(context.brightness), + BlendMode.srcIn, + ), + ), + pressedIcon: Assets.icons.checkmarkCircleFill.svg( + colorFilter: ColorFilter.mode( + ZupThemeColors.success.themed(context.brightness), + BlendMode.srcIn, + ), + ), + onPressed: (buttonContext) { + return Clipboard.setData(ClipboardData(text: widget.liquidityPool.hook!.address)); + }, + ), + const SizedBox(width: 5), + ], + ZupTooltip.text( + key: const Key("hooks-tooltip"), + message: S.of(context).poolInfoModalAboutPageHooksDescription, + constraints: const BoxConstraints(maxWidth: 200), + child: Assets.icons.infoCircle.svg( + height: 15, + width: 15, + colorFilter: const ColorFilter.mode(ZupColors.gray, BlendMode.srcIn), + ), + ), + ], + ), + ), + ), + ], + ], + ), + const SizedBox(height: 20), + Text( + S.of(context).poolInfoModalAboutPageTokens, + style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 15, color: ZupColors.gray), + ), + const SizedBox(height: 5), + buildTokenButton(context, widget.liquidityPool.token0), + const SizedBox(height: 10), + buildTokenButton(context, widget.liquidityPool.token1), + const SizedBox(height: 20), + Text( + S.of(context).poolInfoModalAboutPageProtocol, + style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 15, color: ZupColors.gray), + ), + const SizedBox(height: 5), + ZupOutlinedButton( + key: const Key("protocol-button"), + onPressed: () { + return launchUrl(Uri.parse(widget.liquidityPool.protocol.url), mode: LaunchMode.externalApplication); + }, + leadingIcon: ZupRemoteAvatar( + avatarUrl: widget.liquidityPool.protocol.logo, + zupNetworkImage: zupNetworkImage, + size: 20, + ), + + trailingIcon: Assets.icons.arrowUpRight.svg( + height: 9, + width: 9, + colorFilter: ColorFilter.mode(ZupThemeColors.primaryText.themed(context.brightness), BlendMode.srcIn), + ), + title: Text( + widget.liquidityPool.protocol.name, + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 15, + color: ZupThemeColors.primaryText.themed(context.brightness), + ), + ), + ), + const SizedBox(height: 20), + Text( + S.of(context).poolInfoModalAboutPageNetwork, + style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 15, color: ZupColors.gray), + ), + const SizedBox(height: 5), + ZupOutlinedButton( + key: const Key("network-button"), + onPressed: () { + launchUrl(Uri.parse(widget.liquidityPool.network.websiteUrl), mode: LaunchMode.externalApplication); + }, + title: Text( + widget.liquidityPool.network.label, + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 15, + color: ZupThemeColors.primaryText.themed(context.brightness), + ), + ), + leadingIcon: SizedBox(width: 24, height: 24, child: widget.liquidityPool.network.icon(context.brightness)), + trailingIcon: Assets.icons.arrowUpRight.svg( + height: 9, + width: 9, + colorFilter: ColorFilter.mode(ZupThemeColors.primaryText.themed(context.brightness), BlendMode.srcIn), + ), + ), + + const SizedBox(height: 40), + const Spacer(), + Center( + child: Text( + S + .of(context) + .poolInfoModalAboutPageTimeCreatedAgo( + timeAgo: DateTime.fromMillisecondsSinceEpoch( + widget.liquidityPool.createdAtMillisecondsTimestamp, + ).timeAgo.formattedTimeAgo(context), + ), + style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 13, color: ZupColors.gray), + ), + ), + ], + ); + } + + Widget buildTokenButton(BuildContext context, SingleChainTokenDto token) => Row( + children: [ + ZupOutlinedButton( + key: Key("${token.address}-button"), + onPressed: token.address != EthereumConstants.zeroAddress + ? () => widget.liquidityPool.network.openAddress(token.address) + : null, + title: Text( + token.symbol, + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 15, + color: token.address != EthereumConstants.zeroAddress + ? ZupThemeColors.primaryText.themed(context.brightness) + : ZupThemeColors.primaryText.themed(context.brightness), + ), + ), + leadingIcon: ZupRemoteAvatar( + avatarUrl: token.logoUrl, + size: 20, + errorPlaceholder: token.name[0], + zupNetworkImage: zupNetworkImage, + ), + trailingIcon: token.address == EthereumConstants.zeroAddress + ? null + : Row( + children: [ + Text( + token.address.shortAddress(prefixAndSuffixLength: 3), + style: TextStyle(color: ZupThemeColors.primaryText.themed(context.brightness)), + ), + const SizedBox(width: 10), + Assets.icons.arrowUpRight.svg( + height: 9, + width: 9, + colorFilter: ColorFilter.mode( + ZupThemeColors.primaryText.themed(context.brightness), + BlendMode.srcIn, + ), + ), + ], + ), + ), + if (token.address != EthereumConstants.zeroAddress) ...[ + const SizedBox(width: 10), + ZupSwitchingIconButton( + key: Key("${token.address}-copy-button"), + restIconTooltipMessage: S.of(context).poolInfoModalAboutPageCopyToken, + pressedIconTooltipMessage: S.of(context).poolInfoModalAboutPageTokenCopied, + restIcon: Assets.icons.documentOnDocument.svg( + height: 18, + width: 18, + colorFilter: const ColorFilter.mode(ZupColors.gray, BlendMode.srcIn), + ), + pressedIcon: Assets.icons.checkmarkCircleFill.svg( + height: 18, + width: 18, + colorFilter: ColorFilter.mode(ZupThemeColors.success.themed(context.brightness), BlendMode.srcIn), + ), + onPressed: (buttonContext) => Clipboard.setData(ClipboardData(text: token.address)), + ), + ], + ], + ); +} diff --git a/lib/widgets/pool_info_modal/pages/stats_page.dart b/lib/widgets/pool_info_modal/pages/stats_page.dart new file mode 100644 index 0000000..510212f --- /dev/null +++ b/lib/widgets/pool_info_modal/pages/stats_page.dart @@ -0,0 +1,166 @@ +part of '../pool_info_modal.dart'; + +class _StatsPage extends StatefulWidget { + const _StatsPage({required this.liquidityPool, required this.selectedTimeframe}); + + final LiquidityPoolDto liquidityPool; + final PoolDataTimeframe selectedTimeframe; + + @override + State<_StatsPage> createState() => _StatsPageState(); +} + +class _StatsPageState extends State<_StatsPage> with DeviceInfoMixin { + late PoolDataTimeframe selectedTimeframe = widget.selectedTimeframe; + + @override + Widget build(BuildContext context) { + return ConstrainedBox( + constraints: const BoxConstraints(minHeight: 370), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 20), + Align( + alignment: Alignment.centerLeft, + child: TimeframeSelector( + title: S.of(context).poolInfoModalStatsPageTimeframeTitle, + selectedTimeframe: selectedTimeframe, + onTimeframeSelected: (timeframe) => setState(() => selectedTimeframe = timeframe), + ), + ), + const SizedBox(height: 10), + FlexList( + children: [ + _buildInfoField( + title: S.of(context).tvl, + value: widget.liquidityPool.totalValueLockedUSD.formatCompactCurrency(), + tooltipMessage: S + .of(context) + .poolInfoModalStatsPageTvlDescription( + formattedTvl: widget.liquidityPool.totalValueLockedUSD.formatCompactCurrency(), + ), + ), + _buildInfoField( + title: S + .of(context) + .poolInfoModalStatsPageSwapVolume(timeframeLabel: selectedTimeframe.compactDaysLabel(context)), + value: widget.liquidityPool.volumeTimeframed(selectedTimeframe).formatCompactCurrency(), + tooltipMessage: S + .of(context) + .poolInfoModalStatePageSwapVolumeDescription( + formattedVolume: widget.liquidityPool.volumeTimeframed(selectedTimeframe).formatCompactCurrency(), + timeframeLabel: selectedTimeframe.compactDaysLabel(context), + ), + ), + _buildInfoField( + title: S + .of(context) + .poolInfoModalStatsPageFees(timeframeLabel: selectedTimeframe.compactDaysLabel(context)), + value: widget.liquidityPool.feesTimeframed(selectedTimeframe).formatCompactCurrency(), + tooltipMessage: S + .of(context) + .poolInfoModalStatsPageFeesDescription( + formattedFees: widget.liquidityPool.feesTimeframed(selectedTimeframe).formatCompactCurrency(), + timeframeLabel: selectedTimeframe.compactDaysLabel(context), + ), + ), + _buildInfoField( + title: S + .of(context) + .poolInfoModalStatsPageNetInflow(timeframeLabel: selectedTimeframe.compactDaysLabel(context)), + value: widget.liquidityPool + .netInflowTimeframed(selectedTimeframe) + .formatCompactCurrency() + .asSignedStringNumber, + tooltipMessage: S + .of(context) + .poolInfoModalStatsPageNetInflowDescription( + timeframeLabel: selectedTimeframe.compactDaysLabel(context), + formattedNetInflow: widget.liquidityPool + .netInflowTimeframed(selectedTimeframe) + .formatCompactCurrency() + .asSignedStringNumber, + ), + titleColor: widget.liquidityPool.netInflowTimeframed(selectedTimeframe).trendColor(context), + ), + _buildInfoField( + title: S + .of(context) + .poolInfoModalStatsPageYearlyYield(timeframeLabel: selectedTimeframe.compactDaysLabel(context)), + value: widget.liquidityPool.timeframedYieldFormatted(selectedTimeframe), + titleColor: context.brightness.isDark ? ZupColors.brand5 : ZupColors.brand, + tooltipMessage: S + .of(context) + .poolInfoModalStatsPageYearlyYieldDescription( + yearlyYieldFormatted: widget.liquidityPool.timeframedYieldFormatted(selectedTimeframe), + timeframeLabel: selectedTimeframe.compactDaysLabel(context), + ), + ), + ], + ), + ], + ), + ); + } + + Widget _buildInfoField({ + required String title, + required String value, + required String tooltipMessage, + Color? titleColor, + }) => ZupTooltip.text( + message: isMobileDevice ? tooltipMessage : "", + child: Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + border: Border.all( + width: context.brightness.isDark ? 1 : 0.5, + color: ZupThemeColors.borderOnBackground.themed(context.brightness), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + title, + style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 15, color: ZupColors.gray), + ), + ], + ), + const SizedBox(width: 5), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + value, + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 20, + color: titleColor ?? ZupThemeColors.primaryText.themed(context.brightness), + ), + ), + const SizedBox(width: 5), + ZupTooltip.text( + key: Key("$title-tooltip"), + message: tooltipMessage, + constraints: const BoxConstraints(maxWidth: 250), + child: Assets.icons.infoCircle.svg( + colorFilter: const ColorFilter.mode(ZupColors.gray, BlendMode.srcIn), + width: 12, + height: 12, + ), + ), + ], + ), + ], + ), + ), + ); +} diff --git a/lib/widgets/pool_info_modal/pool_info_modal.dart b/lib/widgets/pool_info_modal/pool_info_modal.dart new file mode 100644 index 0000000..603fa47 --- /dev/null +++ b/lib/widgets/pool_info_modal/pool_info_modal.dart @@ -0,0 +1,171 @@ +import 'package:flex_list/flex_list.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:web3kit/web3kit.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; +import 'package:zup_app/core/extensions/num_extension.dart'; +import 'package:zup_app/core/extensions/time_ago_extension.dart'; +import 'package:zup_app/core/injections.dart'; +import 'package:zup_app/core/zup_navigator.dart'; +import 'package:zup_app/gen/assets.gen.dart'; +import 'package:zup_app/l10n/gen/app_localizations.dart'; +import 'package:zup_app/widgets/pool_tokens_button.dart'; +import 'package:zup_app/widgets/timeframe_selector.dart'; +import 'package:zup_core/zup_core.dart'; +import 'package:zup_ui_kit/zup_ui_kit.dart'; + +part 'pages/about_page.dart'; +part 'pages/stats_page.dart'; + +enum _PoolInfoPages { stats, about } + +class PoolInfoModal extends StatefulWidget with DeviceInfoMixin { + const PoolInfoModal({super.key, required this.liquidityPool, required this.selectedTimeframe}); + + final LiquidityPoolDto liquidityPool; + final PoolDataTimeframe selectedTimeframe; + + static show( + BuildContext context, { + required LiquidityPoolDto liquidityPool, + required PoolDataTimeframe selectedTimeframe, + required bool showAsBottomSheet, + }) { + if (showAsBottomSheet) { + return ZupModal.show( + context, + dismissible: true, + content: PoolInfoModal(liquidityPool: liquidityPool, selectedTimeframe: selectedTimeframe), + title: S.of(context).poolInfoModalBottomSheetTitle, + backgroundColor: null, + description: null, + padding: EdgeInsets.zero, + showAsBottomSheet: true, + ); + } + + return ZupSidePanel.show( + context, + child: PoolInfoModal(liquidityPool: liquidityPool, selectedTimeframe: selectedTimeframe), + ); + } + + @override + State createState() => _PoolInfoModalState(); +} + +class _PoolInfoModalState extends State with SingleTickerProviderStateMixin, DeviceInfoMixin { + final navigator = inject(); + + _PoolInfoPages selectedTab = _PoolInfoPages.stats; + + @override + Widget build(BuildContext context) { + return Container( + constraints: const BoxConstraints(maxWidth: 540), + child: ScrollbarTheme( + data: Theme.of(context).scrollbarTheme.copyWith(crossAxisMargin: 8, mainAxisMargin: 20), + child: CustomScrollView( + physics: const ClampingScrollPhysics(), + shrinkWrap: true, + slivers: [ + SliverFillRemaining( + hasScrollBody: false, + child: Container( + padding: isMobileSize(context) ? const EdgeInsets.symmetric(horizontal: 20) : const EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + PoolTokensButton(liquidityPool: widget.liquidityPool), + const SizedBox(width: 10), + ZupSwitchingIconButton( + key: const Key("pool-info-modal-copy-pool-address"), + restIconTooltipMessage: S.of(context).poolInfoModalCopyPoolAddress, + pressedIconTooltipMessage: S.of(context).poolInfoModalCopied, + restIcon: Assets.icons.documentOnDocument.svg( + height: 18, + width: 18, + colorFilter: const ColorFilter.mode(ZupColors.gray, BlendMode.srcIn), + ), + pressedIcon: Assets.icons.checkmarkCircleFill.svg( + height: 17, + width: 17, + colorFilter: ColorFilter.mode( + ZupThemeColors.success.themed(context.brightness), + BlendMode.srcIn, + ), + ), + onPressed: (buttonContext) { + return Clipboard.setData(ClipboardData(text: widget.liquidityPool.poolAddress)); + }, + ), + + if (!isMobileSize(context)) ...[ + const Spacer(), + ZupPrimaryButton( + key: const Key("pool-info-modal-add-liquidity"), + title: S.of(context).poolInfoModalAddLiquidity, + onPressed: (buttonContext) { + Navigator.pop(context); + navigator.navigateToDeposit( + yieldPool: widget.liquidityPool, + selectedTimeframe: widget.selectedTimeframe, + parseWrappedToNative: + widget.liquidityPool.isToken0Native || widget.liquidityPool.isToken1Native, + ); + }, + fixedIcon: true, + isTrailingIcon: true, + icon: Assets.icons.arrowRight.svg(), + ), + ], + ], + ), + const SizedBox(height: 20), + ZupTabBar( + initialSelectedTabIndex: 0, + tabs: [ + ZupTabBarItem( + key: const Key("stats-tab"), + title: S.of(context).poolInfoModalPoolStatsTabTitle, + icon: Assets.icons.chartBar.svg(), + onSelected: () { + setState(() => selectedTab = _PoolInfoPages.stats); + }, + ), + ZupTabBarItem( + key: const Key("about-tab"), + title: S.of(context).poolInfoModalAboutPoolTabTitle, + icon: Assets.icons.infoCircle.svg(), + onSelected: () { + setState(() => selectedTab = _PoolInfoPages.about); + }, + ), + ], + ), + + Expanded( + child: switch (selectedTab) { + _PoolInfoPages.stats => _StatsPage( + liquidityPool: widget.liquidityPool, + selectedTimeframe: widget.selectedTimeframe, + ), + _PoolInfoPages.about => _AboutPage(widget.liquidityPool), + }, + ), + const SizedBox(height: 20), + ], + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/widgets/pool_token.dart b/lib/widgets/pool_token.dart new file mode 100644 index 0000000..16075c4 --- /dev/null +++ b/lib/widgets/pool_token.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; +import 'package:zup_app/core/injections.dart'; +import 'package:zup_ui_kit/zup_network_image.dart'; +import 'package:zup_ui_kit/zup_remote_avatar.dart'; + +class PoolToken extends StatelessWidget { + PoolToken({super.key, required this.token}); + + final SingleChainTokenDto token; + final zupNetworkImage = inject(); + + @override + Widget build(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + ZupRemoteAvatar( + avatarUrl: token.logoUrl, + errorPlaceholder: token.name[0], + size: 30, + zupNetworkImage: zupNetworkImage, + ), + const SizedBox(width: 10), + Text(token.symbol, style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w500)), + ], + ); + } +} diff --git a/lib/widgets/pool_tokens_avatar.dart b/lib/widgets/pool_tokens_avatar.dart new file mode 100644 index 0000000..89a43c3 --- /dev/null +++ b/lib/widgets/pool_tokens_avatar.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/injections.dart'; +import 'package:zup_ui_kit/zup_ui_kit.dart'; + +class PoolTokensAvatar extends StatelessWidget { + const PoolTokensAvatar({super.key, required this.liquidityPool, this.size = 27}); + + final LiquidityPoolDto liquidityPool; + final double size; + + ZupNetworkImage get zupNetworkImage => inject(); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: size * 2, + child: Stack( + clipBehavior: Clip.none, + children: [ + ZupRemoteAvatar( + avatarUrl: liquidityPool.token0.logoUrl, + errorPlaceholder: liquidityPool.token0.name.isEmpty ? null : liquidityPool.token0.name[0], + size: size, + zupNetworkImage: zupNetworkImage, + ), + Positioned( + left: 20, + child: ZupRemoteAvatar( + avatarUrl: liquidityPool.token1.logoUrl, + errorPlaceholder: liquidityPool.token1.name.isEmpty ? null : liquidityPool.token1.name[0], + zupNetworkImage: zupNetworkImage, + size: size, + ), + ), + ], + ), + ); + } +} diff --git a/lib/widgets/pool_tokens_button.dart b/lib/widgets/pool_tokens_button.dart new file mode 100644 index 0000000..505a68a --- /dev/null +++ b/lib/widgets/pool_tokens_button.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/gen/assets.gen.dart'; +import 'package:zup_app/l10n/gen/app_localizations.dart'; +import 'package:zup_app/widgets/pool_tokens_avatar.dart'; +import 'package:zup_core/extensions/extensions.dart'; +import 'package:zup_ui_kit/zup_ui_kit.dart'; + +class PoolTokensButton extends StatelessWidget { + const PoolTokensButton({super.key, required this.liquidityPool}); + + final LiquidityPoolDto liquidityPool; + + bool get canLaunchAtDexscreener => liquidityPool.network.dexscreenerUrl != null; + + @override + Widget build(BuildContext context) { + return ZupTooltip.text( + message: canLaunchAtDexscreener ? S.of(context).poolTokensButtonViewAtDexcreener : "", + margin: const EdgeInsets.only(top: 10), + constraints: const BoxConstraints(maxWidth: 200), + child: ZupOutlinedButton( + onPressed: canLaunchAtDexscreener + ? () => launchUrl(Uri.parse("${liquidityPool.network.dexscreenerUrl}/${liquidityPool.poolAddress}")) + : null, + leadingIconSpacing: 5, + title: Text( + "${liquidityPool.token0.symbol.clamped(8)}/${liquidityPool.token1.symbol.clamped(8)}", + style: TextStyle( + fontWeight: FontWeight.w600, + color: canLaunchAtDexscreener ? ZupColors.brand : ZupThemeColors.primaryText.themed(context.brightness), + fontSize: 16, + ), + ), + trailingIcon: canLaunchAtDexscreener + ? Container( + padding: const EdgeInsets.all(5), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: ZupThemeColors.backgroundInverse.themed(context.brightness), + ), + child: Assets.logos.dexscreener.svg( + height: 15, + width: 15, + colorFilter: ColorFilter.mode(ZupThemeColors.background.themed(context.brightness), BlendMode.srcIn), + ), + ) + : null, + leadingIcon: PoolTokensAvatar(liquidityPool: liquidityPool), + ), + ); + } +} diff --git a/lib/widgets/position_token.dart b/lib/widgets/position_token.dart deleted file mode 100644 index 5448f1f..0000000 --- a/lib/widgets/position_token.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/injections.dart'; -import 'package:zup_app/widgets/token_avatar.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; - -class PositionToken extends StatelessWidget { - PositionToken({super.key, required this.token}); - - final TokenDto token; - final zupCachedImage = inject(); - - @override - Widget build(BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - TokenAvatar(asset: token, size: 30), - const SizedBox(width: 10), - Text( - token.symbol, - style: const TextStyle( - fontSize: 17, - fontWeight: FontWeight.w500, - ), - ), - ], - ); - } -} diff --git a/lib/widgets/timeframe_selector.dart b/lib/widgets/timeframe_selector.dart index 9d391a2..ba37c13 100644 --- a/lib/widgets/timeframe_selector.dart +++ b/lib/widgets/timeframe_selector.dart @@ -1,15 +1,22 @@ import 'package:flutter/cupertino.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; import 'package:zup_app/gen/assets.gen.dart'; -import 'package:zup_app/l10n/gen/app_localizations.dart'; import 'package:zup_core/extensions/build_context_extension.dart'; import 'package:zup_ui_kit/zup_ui_kit.dart'; class TimeframeSelector extends StatefulWidget { - const TimeframeSelector({super.key, required this.selectedTimeframe, required this.onTimeframeSelected}); + const TimeframeSelector({ + super.key, + required this.selectedTimeframe, + required this.onTimeframeSelected, + required this.title, + this.tooltipMessage, + }); - final YieldTimeFrame selectedTimeframe; - final Function(YieldTimeFrame? newTimeframe) onTimeframeSelected; + final String title; + final String? tooltipMessage; + final PoolDataTimeframe selectedTimeframe; + final Function(PoolDataTimeframe newTimeframe) onTimeframeSelected; @override State createState() => _TimeframeSelectorState(); @@ -26,7 +33,7 @@ class _TimeframeSelectorState extends State { crossAxisAlignment: WrapCrossAlignment.center, children: [ Text( - S.of(context).yieldsPageTimeframeSelectorTitle, + widget.title, style: TextStyle( color: ZupThemeColors.primaryText.themed(context.brightness), fontSize: 14, @@ -37,14 +44,14 @@ class _TimeframeSelectorState extends State { Row( mainAxisSize: MainAxisSize.min, children: [ - CupertinoSlidingSegmentedControl( + CupertinoSlidingSegmentedControl( proportionalWidth: true, onValueChanged: (timeframe) async { - widget.onTimeframeSelected(timeframe); + widget.onTimeframeSelected(timeframe ?? PoolDataTimeframe.day); }, groupValue: widget.selectedTimeframe, children: Map.fromEntries( - YieldTimeFrame.values.map( + PoolDataTimeframe.values.map( (timeframe) => MapEntry( timeframe, IgnorePointer( @@ -64,14 +71,16 @@ class _TimeframeSelectorState extends State { ), ), ), - const SizedBox(width: 10), - ZupTooltip.text( - key: const Key("timeframe-tooltip"), - message: S.of(context).yieldsPageTimeframeExplanation, - child: Assets.icons.infoCircle.svg( - colorFilter: const ColorFilter.mode(ZupColors.gray, BlendMode.srcIn), + if (widget.tooltipMessage != null) ...[ + const SizedBox(width: 10), + ZupTooltip.text( + key: const Key("timeframe-tooltip"), + message: widget.tooltipMessage!, + child: Assets.icons.infoCircle.svg( + colorFilter: const ColorFilter.mode(ZupColors.gray, BlendMode.srcIn), + ), ), - ), + ], ], ), ], diff --git a/lib/widgets/token_avatar.dart b/lib/widgets/token_avatar.dart deleted file mode 100644 index c057a06..0000000 --- a/lib/widgets/token_avatar.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:skeletonizer/skeletonizer.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/injections.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; -import 'package:zup_ui_kit/zup_circular_loading_indicator.dart'; -import 'package:zup_ui_kit/zup_colors.dart'; - -class TokenAvatar extends StatelessWidget { - TokenAvatar({super.key, required this.asset, this.size = 30}); - - final TokenDto asset; - final double size; - - final zupCachedImage = inject(); - - Widget genericAvatar() => SizedBox( - height: size, - width: size, - child: FittedBox( - child: CircleAvatar( - backgroundColor: ZupColors.brand7, - foregroundColor: ZupColors.brand, - child: Text(asset.name.isNotEmpty ? asset.name[0] : ""), - ), - ), - ); - - @override - Widget build(BuildContext context) { - return asset.logoUrl.isEmpty - ? genericAvatar() - : zupCachedImage.build( - context, - asset.logoUrl, - height: size, - width: size, - radius: 50, - errorWidget: (_, __, ___) => genericAvatar(), - placeholder: Skeleton.ignore( - child: ZupCircularLoadingIndicator( - size: size, - backgroundColor: ZupColors.brand5, - indicatorColor: ZupColors.brand, - ), - ), - ); - } -} diff --git a/lib/widgets/token_card.dart b/lib/widgets/token_card.dart index f6d78e8..fbbe930 100644 --- a/lib/widgets/token_card.dart +++ b/lib/widgets/token_card.dart @@ -1,15 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/injections.dart'; -import 'package:zup_app/widgets/token_avatar.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; import 'package:zup_core/extensions/extensions.dart'; import 'package:zup_ui_kit/zup_ui_kit.dart'; class TokenCard extends StatefulWidget { const TokenCard({super.key, required this.asset, required this.onClick}); - final TokenDto asset; + final MultiChainTokenDto asset; final Function() onClick; @override @@ -19,7 +17,7 @@ class TokenCard extends StatefulWidget { class _TokenCardState extends State { bool isHovering = false; - final zupCachedImage = inject(); + final zupNetworkImage = inject(); @override Widget build(BuildContext context) { @@ -32,7 +30,12 @@ class _TokenCardState extends State { }, child: Row( children: [ - TokenAvatar(asset: widget.asset, size: 35), + ZupRemoteAvatar( + avatarUrl: widget.asset.logoUrl, + errorPlaceholder: widget.asset.name[0], + size: 35, + zupNetworkImage: zupNetworkImage, + ), const SizedBox(width: 10), Expanded( child: Column( diff --git a/lib/widgets/token_group_card.dart b/lib/widgets/token_group_card.dart index 568a680..e0127da 100644 --- a/lib/widgets/token_group_card.dart +++ b/lib/widgets/token_group_card.dart @@ -3,14 +3,8 @@ import 'package:skeletonizer/skeletonizer.dart'; import 'package:zup_app/core/dtos/token_group_dto.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/gen/assets.gen.dart'; -import 'package:zup_app/widgets/token_avatar.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; import 'package:zup_core/extensions/extensions.dart'; -import 'package:zup_ui_kit/zup_circular_loading_indicator.dart'; -import 'package:zup_ui_kit/zup_colors.dart'; -import 'package:zup_ui_kit/zup_selectable_card.dart'; -import 'package:zup_ui_kit/zup_theme_colors.dart'; -import 'package:zup_ui_kit/zup_tooltip.dart'; +import 'package:zup_ui_kit/zup_ui_kit.dart'; class TokenGroupCard extends StatefulWidget { const TokenGroupCard({super.key, required this.group, required this.onClick}); @@ -23,7 +17,7 @@ class TokenGroupCard extends StatefulWidget { } class _TokenGroupCardState extends State { - final ZupCachedImage zupCachedImage = inject(); + final ZupNetworkImage zupNetworkImage = inject(); bool isHovering = false; @override @@ -35,7 +29,7 @@ class _TokenGroupCardState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [ - zupCachedImage.build( + zupNetworkImage.load( context, widget.group.logoUrl, height: 35, @@ -52,7 +46,7 @@ class _TokenGroupCardState extends State { placeholder: const Skeleton.ignore( child: ZupCircularLoadingIndicator( size: 35, - backgroundColor: ZupColors.brand5, + trackColor: ZupColors.brand5, indicatorColor: ZupColors.brand, ), ), @@ -96,7 +90,11 @@ class _TokenGroupCardState extends State { child: Row( spacing: 10, children: [ - TokenAvatar(asset: widget.group.tokens[index], size: 20), + ZupRemoteAvatar( + avatarUrl: widget.group.tokens[index].logoUrl, + errorPlaceholder: widget.group.tokens[index].name[0], + size: 20, + ), Expanded( child: Text( overflow: TextOverflow.ellipsis, diff --git a/lib/widgets/token_selector_button/token_selector_button.dart b/lib/widgets/token_selector_button/token_selector_button.dart index 59f6f39..b7a0180 100644 --- a/lib/widgets/token_selector_button/token_selector_button.dart +++ b/lib/widgets/token_selector_button/token_selector_button.dart @@ -1,13 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/dtos/token_group_dto.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/gen/assets.gen.dart'; import 'package:zup_app/l10n/gen/app_localizations.dart'; -import 'package:zup_app/widgets/token_avatar.dart'; import 'package:zup_app/widgets/token_selector_button/token_selector_button_controller.dart'; import 'package:zup_app/widgets/token_selector_modal/token_selector_modal.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; import 'package:zup_core/zup_core.dart'; import 'package:zup_ui_kit/zup_ui_kit.dart'; @@ -21,8 +19,8 @@ class TokenSelectorButton extends StatefulWidget { } class _TokenSelectorButtonState extends State with DeviceInfoMixin { - final zupCachedImage = inject(); - TokenDto? get selectedToken => widget.controller.selectedToken; + final zupNetworkImage = inject(); + MultiChainTokenDto? get selectedToken => widget.controller.selectedToken; TokenGroupDto? get selectedGroup => widget.controller.selectedTokenGroup; bool get hasSelection => widget.controller.hasSelection; @@ -102,23 +100,15 @@ class _TokenSelectorButtonState extends State with DeviceIn colorFilter: const ColorFilter.mode(ZupColors.brand, BlendMode.srcIn), ) else ...[ - if (selectedToken != null) TokenAvatar(asset: selectedToken!, size: 30), - if (selectedGroup != null) - zupCachedImage.build( - context, - selectedGroup!.logoUrl, - height: 30, - width: 30, - radius: 50, - errorWidget: (_, __, ___) => Container( - height: 30, - width: 30, - color: ZupColors.gray6, - child: const Center( - child: Text("?", style: TextStyle(color: ZupColors.gray, fontSize: 16)), - ), - ), + if (selectedToken != null) + ZupRemoteAvatar( + avatarUrl: selectedToken!.logoUrl, + errorPlaceholder: selectedToken!.name[0], + zupNetworkImage: zupNetworkImage, + size: 30, ), + if (selectedGroup != null) + ZupRemoteAvatar(avatarUrl: selectedGroup!.logoUrl, errorPlaceholder: "?", size: 30), ], const SizedBox(width: 10), Expanded( diff --git a/lib/widgets/token_selector_button/token_selector_button_controller.dart b/lib/widgets/token_selector_button/token_selector_button_controller.dart index 77653db..6fb1b5d 100644 --- a/lib/widgets/token_selector_button/token_selector_button_controller.dart +++ b/lib/widgets/token_selector_button/token_selector_button_controller.dart @@ -1,27 +1,28 @@ import 'dart:async'; import 'package:async/async.dart' show StreamGroup; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/dtos/token_group_dto.dart'; class TokenSelectorButtonController { - TokenDto? _selectedToken; + MultiChainTokenDto? _selectedToken; TokenGroupDto? _selectedTokenGroup; - final StreamController _selectedTokenStreamController = StreamController.broadcast(); + final StreamController _selectedTokenStreamController = + StreamController.broadcast(); final StreamController _selectedTokenGroupStreamController = StreamController.broadcast(); bool get hasSelection => _selectedToken != null || _selectedTokenGroup != null; - TokenDto? get selectedToken => _selectedToken; + MultiChainTokenDto? get selectedToken => _selectedToken; TokenGroupDto? get selectedTokenGroup => _selectedTokenGroup; - Stream get selectedTokenStream => _selectedTokenStreamController.stream; + Stream get selectedTokenStream => _selectedTokenStreamController.stream; Stream get selectedTokenGroupStream => _selectedTokenGroupStreamController.stream; Stream get selectionStream => StreamGroup.mergeBroadcast([selectedTokenStream, selectedTokenGroupStream]); - void changeToken(TokenDto? newToken) { + void changeToken(MultiChainTokenDto? newToken) { if (newToken == _selectedToken) return; _selectedToken = newToken; diff --git a/lib/widgets/token_selector_modal/token_selector_modal.dart b/lib/widgets/token_selector_modal/token_selector_modal.dart index 2f920da..b4e4c9a 100644 --- a/lib/widgets/token_selector_modal/token_selector_modal.dart +++ b/lib/widgets/token_selector_modal/token_selector_modal.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:zup_app/app/app_cubit/app_cubit.dart'; import 'package:zup_app/core/debouncer.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/dtos/token_group_dto.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/gen/assets.gen.dart'; @@ -18,13 +18,13 @@ import 'package:zup_ui_kit/zup_ui_kit.dart'; class TokenSelectorModal extends StatefulWidget { const TokenSelectorModal({super.key, required this.onSelectToken, required this.onSelectTokenGroup}); - final Function(TokenDto token) onSelectToken; + final Function(MultiChainTokenDto token) onSelectToken; final Function(TokenGroupDto token) onSelectTokenGroup; static void show( BuildContext context, { required bool showAsBottomSheet, - required Function(TokenDto token) onSelectToken, + required Function(MultiChainTokenDto token) onSelectToken, required Function(TokenGroupDto token) onSelectTokenGroup, }) async { return ZupModal.show( @@ -53,7 +53,7 @@ class _TokenSelectorModalState extends State with DeviceInfo final _cubit = inject(); final _appCubit = inject(); - void _selectToken(TokenDto token) { + void _selectToken(MultiChainTokenDto token) { widget.onSelectToken(token); Navigator.of(context).pop(); } @@ -253,7 +253,7 @@ class _TokenSelectorModalState extends State with DeviceInfo 3, (index) => Padding( padding: _paddingBetweenListItems, - child: TokenCard(asset: TokenDto.fixture(), onClick: () {}), + child: TokenCard(asset: MultiChainTokenDto.fixture(), onClick: () {}), ), ), ), @@ -306,7 +306,7 @@ class _TokenSelectorModalState extends State with DeviceInfo 4, (index) => Padding( padding: _paddingBetweenListItems, - child: TokenCard(asset: TokenDto.fixture(), onClick: () {}), + child: TokenCard(asset: MultiChainTokenDto.fixture(), onClick: () {}), ), ), ), diff --git a/lib/widgets/token_selector_modal/token_selector_modal_cubit.dart b/lib/widgets/token_selector_modal/token_selector_modal_cubit.dart index 91fa325..333ff52 100644 --- a/lib/widgets/token_selector_modal/token_selector_modal_cubit.dart +++ b/lib/widgets/token_selector_modal/token_selector_modal_cubit.dart @@ -3,7 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:web3kit/web3kit.dart'; import 'package:zup_app/app/app_cubit/app_cubit.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/dtos/token_list_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/repositories/tokens_repository.dart'; diff --git a/lib/widgets/token_selector_modal/token_selector_modal_state.dart b/lib/widgets/token_selector_modal/token_selector_modal_state.dart index a7e44d7..8de595a 100644 --- a/lib/widgets/token_selector_modal/token_selector_modal_state.dart +++ b/lib/widgets/token_selector_modal/token_selector_modal_state.dart @@ -6,7 +6,7 @@ class TokenSelectorModalState with _$TokenSelectorModalState { const factory TokenSelectorModalState.loading() = _Loading; const factory TokenSelectorModalState.searchLoading() = _SearchLoading; const factory TokenSelectorModalState.success(TokenListDto popularTokens) = _Success; - const factory TokenSelectorModalState.searchSuccess(List result) = _SearchSuccess; + const factory TokenSelectorModalState.searchSuccess(List result) = _SearchSuccess; const factory TokenSelectorModalState.error() = _Error; const factory TokenSelectorModalState.searchError(String searchedTerm) = _SearchError; const factory TokenSelectorModalState.searchNotFound(String searchedTerm) = _SearchNotFound; diff --git a/lib/widgets/yield_card.dart b/lib/widgets/yield_card.dart index d92daf7..410ce7a 100644 --- a/lib/widgets/yield_card.dart +++ b/lib/widgets/yield_card.dart @@ -3,14 +3,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'package:intl/intl.dart'; import 'package:skeletonizer/skeletonizer.dart' hide ShimmerEffect; -import 'package:zup_app/core/dtos/yield_dto.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/core/mixins/keys_mixin.dart'; import 'package:zup_app/gen/assets.gen.dart'; import 'package:zup_app/l10n/gen/app_localizations.dart'; -import 'package:zup_app/widgets/token_avatar.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; +import 'package:zup_app/widgets/pool_tokens_avatar.dart'; import 'package:zup_core/extensions/extensions.dart'; import 'package:zup_core/mixins/device_info_mixin.dart'; import 'package:zup_ui_kit/zup_ui_kit.dart'; @@ -24,25 +23,27 @@ class YieldCard extends StatefulWidget { this.mainButton, this.expandWidth = false, this.showTimeframe = false, + this.secondaryButton, }); - final YieldDto yieldPool; + final LiquidityPoolDto yieldPool; final bool showHotestYieldAnimation; final bool showTimeframe; final bool expandWidth; - final YieldTimeFrame yieldTimeFrame; - final Widget? mainButton; + final PoolDataTimeframe yieldTimeFrame; + final ZupPrimaryButton? mainButton; + final ZupIconButton? secondaryButton; @override State createState() => _YieldCardState(); } class _YieldCardState extends State with DeviceInfoMixin, KeysMixin { - final zupCachedImage = inject(); + final zupNetworkImage = inject(); final infinityAnimationAutoPlay = inject(instanceName: InjectInstanceNames.infinityAnimationAutoPlay); - List get timeframesExcludingCurrent { - return YieldTimeFrame.values.where((timeframe) => timeframe != widget.yieldTimeFrame).toList(); + List get timeframesExcludingCurrent { + return PoolDataTimeframe.values.where((timeframe) => timeframe != widget.yieldTimeFrame).toList(); } @override @@ -65,7 +66,7 @@ class _YieldCardState extends State with DeviceInfoMixin, KeysMixin { constraints: const BoxConstraints(maxWidth: 450), decoration: BoxDecoration( borderRadius: BorderRadius.circular(24), - color: context.brightness.isDark ? ZupColors.black3 : ZupColors.white, + color: context.brightness.isDark ? ZupColors.black2 : ZupColors.white, border: context.brightness.isDark ? null : Border.all(width: 0.5, color: ZupThemeColors.borderOnBackgroundSurface.themed(context.brightness)), @@ -79,16 +80,10 @@ class _YieldCardState extends State with DeviceInfoMixin, KeysMixin { Row( mainAxisSize: MainAxisSize.min, children: [ - Stack( - clipBehavior: Clip.none, - children: [ - TokenAvatar(asset: widget.yieldPool.token0, size: 27), - Positioned(left: 20, child: TokenAvatar(asset: widget.yieldPool.token1, size: 27)), - ], - ), - const SizedBox(width: 27), + PoolTokensAvatar(liquidityPool: widget.yieldPool, size: 27), + const SizedBox(width: 3), Text( - "${widget.yieldPool.token0.symbol.clampMax(8)}/${widget.yieldPool.token1.symbol.clampMax(8)}", + "${widget.yieldPool.token0.symbol.clamped(8)}/${widget.yieldPool.token1.symbol.clamped(8)}", style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 15), overflow: TextOverflow.ellipsis, ), @@ -147,6 +142,7 @@ class _YieldCardState extends State with DeviceInfoMixin, KeysMixin { const SizedBox(width: 5), Skeleton.ignore( child: ZupTooltip.widget( + isChildBounded: true, key: Key("yield-breakdown-tooltip-${widget.yieldPool.poolAddress}"), tooltipChild: yieldBreakdownTooltipChild, child: Assets.icons.infoCircle.svg( @@ -189,13 +185,10 @@ class _YieldCardState extends State with DeviceInfoMixin, KeysMixin { Row( mainAxisSize: MainAxisSize.min, children: [ - zupCachedImage.build( - context, - widget.yieldPool.protocol.logo, - radius: 20, - height: 25, - width: 25, - backgroundColor: ZupColors.white, + ZupRemoteAvatar( + avatarUrl: widget.yieldPool.protocol.logo, + size: 20, + zupNetworkImage: zupNetworkImage, ), const SizedBox(width: 10), Flexible( @@ -207,23 +200,17 @@ class _YieldCardState extends State with DeviceInfoMixin, KeysMixin { ), ], ), - if (widget.mainButton != null) ...[ - const SizedBox(height: 30), - Row( - children: [ - // ZupIconButton( - // icon: Assets.icons.chartBar.svg(height: 15, width: 15), - // onPressed: (_) {}, - // backgroundColor: context.brightness.isDark - // ? ZupThemeColors.background.themed(Brightness.dark) - // : ZupColors.gray6, - // padding: const EdgeInsets.all(15), - // ), - // const SizedBox(width: 20), - Expanded(child: widget.mainButton!), + + if (widget.mainButton != null || widget.secondaryButton != null) const SizedBox(height: 30), + Row( + children: [ + if (widget.secondaryButton != null) ...[ + widget.secondaryButton!, + if (widget.mainButton != null) const SizedBox(width: 10), ], - ), - ], + if (widget.mainButton != null) Expanded(child: widget.mainButton!), + ], + ), ], ), ), diff --git a/lib/widgets/zup_cached_image.dart b/lib/widgets/zup_cached_image.dart deleted file mode 100644 index 1afc19c..0000000 --- a/lib/widgets/zup_cached_image.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:skeletonizer/skeletonizer.dart'; -import 'package:zup_core/extensions/extensions.dart'; -import 'package:zup_ui_kit/zup_ui_kit.dart'; - -class ZupCachedImage { - String _parseImageUrl(String url) { - if (url.startsWith("ipfs://")) { - return url.replaceFirst("ipfs://", "https://ipfs.io/ipfs/"); - } - - return url; - } - - Widget build( - BuildContext context, - String url, { - double? height, - double? width, - double? radius, - Widget? placeholder, - Color? backgroundColor, - ImageErrorWidgetBuilder? errorWidget, - }) { - return Container( - key: ValueKey(url), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(radius ?? 0), - border: Border.all(width: 0.5, color: ZupThemeColors.borderOnBackground.themed(context.brightness)), - ), - // cache not implemented yet because of web issue rendering images from other domains (https://github.com/Baseflow/flutter_cached_network_image/issues/972) - child: ClipRRect( - borderRadius: BorderRadius.circular(radius ?? 0), - child: Skeleton.shade( - child: Container( - color: backgroundColor, - child: Image.network( - _parseImageUrl(url), - height: height, - width: width, - fit: BoxFit.cover, - errorBuilder: errorWidget, - frameBuilder: (context, child, frame, wasSynchronouslyLoaded) { - if (frame == null) { - return Container( - color: ZupThemeColors.background.themed(context.brightness), - child: placeholder ?? ZupCircularLoadingIndicator(size: height ?? 20), - ); - } - return child; - }, - webHtmlElementStrategy: WebHtmlElementStrategy.fallback, - ), - ), - ), - ), - ); - } -} diff --git a/pubspec.lock b/pubspec.lock index 12791b2..ef4b19a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -386,6 +386,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + flex_list: + dependency: "direct main" + description: + name: flex_list + sha256: c41dc497e972e58899a8173ab0329222e220d4bab4d83454e325e75e21655da2 + url: "https://pub.dev" + source: hosted + version: "1.2.0" flutter: dependency: "direct main" description: flutter @@ -1281,7 +1289,7 @@ packages: description: path: "." ref: main - resolved-ref: "0f6c0f2a93e858209109c9f436f53bbc7c5e3659" + resolved-ref: c198c66a75813e721037169eeeb5d5e95b324179 url: "https://github.com/Zup-Protocol/web3kit.git" source: git version: "0.0.1" @@ -1330,7 +1338,7 @@ packages: description: path: "." ref: main - resolved-ref: "72ba56fe442b4b41ae9ef98b1a73a7e19e0f3ee8" + resolved-ref: "845fc3e2aeb77682c1070ae314924c52c7a58b21" url: "https://github.com/Zup-Protocol/zup-core.git" source: git version: "0.0.1" @@ -1339,7 +1347,7 @@ packages: description: path: "." ref: main - resolved-ref: "7e91f16e6cde62eaabeeccbb646b41803037f211" + resolved-ref: "7448b42d8821713fedc77b22049ce0ba6ca9fde6" url: "https://github.com/Zup-Protocol/zup-ui-kit.git" source: git version: "0.0.1" diff --git a/pubspec.yaml b/pubspec.yaml index 40e560b..a2ff0b0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -53,6 +53,7 @@ dependencies: firebase_analytics: ^11.4.5 envied: ^1.1.1 async: ^2.13.0 + flex_list: ^1.2.0 # dependency_overrides: # zup_core: diff --git a/test/app/create/create_page_select_token_stage_test.dart b/test/app/create/create_page_select_token_stage_test.dart index 9dd0e37..2ec44dd 100644 --- a/test/app/create/create_page_select_token_stage_test.dart +++ b/test/app/create/create_page_select_token_stage_test.dart @@ -9,8 +9,8 @@ import 'package:zup_app/app/app_cubit/app_cubit.dart'; import 'package:zup_app/app/create/create_page_select_tokens_stage.dart'; import 'package:zup_app/core/cache.dart'; import 'package:zup_app/core/debouncer.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/dtos/pool_search_settings_dto.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; import 'package:zup_app/core/dtos/token_group_dto.dart'; import 'package:zup_app/core/dtos/token_list_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; @@ -20,8 +20,8 @@ import 'package:zup_app/core/repositories/tokens_repository.dart'; import 'package:zup_app/core/zup_navigator.dart'; import 'package:zup_app/widgets/token_card.dart'; import 'package:zup_app/widgets/token_selector_modal/token_selector_modal_cubit.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; import 'package:zup_core/zup_core.dart'; +import 'package:zup_ui_kit/zup_ui_kit.dart'; import '../../golden_config.dart'; import '../../mocks.dart'; @@ -47,7 +47,7 @@ void main() { cache = CacheMock(); inject.registerFactory(() => appCubit); - inject.registerFactory(() => mockZupCachedImage()); + inject.registerFactory(() => mockZupNetworkImage()); inject.registerFactory(() => Debouncer(milliseconds: 0)); inject.registerFactory(() => zupNavigator); inject.registerFactory(() => cache); @@ -171,8 +171,8 @@ void main() { when(() => tokensRepository.getTokenList(any())).thenAnswer( (_) async => (TokenListDto( popularTokens: [ - TokenDto(addresses: {appCubit.selectedNetwork.chainId: token1Name}, name: token0Name), - TokenDto(addresses: {appCubit.selectedNetwork.chainId: token0Name}, name: token1Name), + MultiChainTokenDto(addresses: {appCubit.selectedNetwork.chainId: token1Name}, name: token0Name), + MultiChainTokenDto(addresses: {appCubit.selectedNetwork.chainId: token0Name}, name: token1Name), ], )), ); @@ -207,8 +207,8 @@ void main() { when(() => tokensRepository.getTokenList(any())).thenAnswer( (_) async => (TokenListDto( popularTokens: [ - TokenDto(addresses: {appCubit.selectedNetwork.chainId: "token1"}, name: "Token1"), - TokenDto(addresses: {appCubit.selectedNetwork.chainId: "token2"}, name: "Token2"), + MultiChainTokenDto(addresses: {appCubit.selectedNetwork.chainId: "token1"}, name: "Token1"), + MultiChainTokenDto(addresses: {appCubit.selectedNetwork.chainId: "token2"}, name: "Token2"), ], )), ); @@ -298,12 +298,12 @@ void main() { const token1Id = "87"; final tokens = [ - TokenDto.fixture().copyWith( + MultiChainTokenDto.fixture().copyWith( name: "TokenA", internalId: token0Id, addresses: {appCubit.selectedNetwork.chainId: token0Id}, ), - TokenDto.fixture().copyWith( + MultiChainTokenDto.fixture().copyWith( name: "TokenB", internalId: token1Id, addresses: {appCubit.selectedNetwork.chainId: token1Id}, diff --git a/test/app/create/create_page_test.dart b/test/app/create/create_page_test.dart index 8658efa..9a9bb7e 100644 --- a/test/app/create/create_page_test.dart +++ b/test/app/create/create_page_test.dart @@ -9,8 +9,8 @@ import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/core/repositories/protocol_repository.dart'; import 'package:zup_app/core/zup_navigator.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; import 'package:zup_core/zup_core.dart'; +import 'package:zup_ui_kit/zup_ui_kit.dart'; import '../../golden_config.dart'; import '../../mocks.dart'; @@ -24,7 +24,7 @@ void main() { cache = CacheMock(); inject.registerFactory(() => cache); - inject.registerFactory(() => mockZupCachedImage()); + inject.registerFactory(() => mockZupNetworkImage()); inject.registerFactory(() => appCubit); inject.registerFactory(() => ZupNavigatorMock()); inject.registerFactory(() => ZupSingletonCache.shared); @@ -38,9 +38,12 @@ void main() { tearDown(() => inject.reset()); Future goldenBuilder() async => await goldenDeviceBuilder(const CreatePage()); - zGoldenTest("When loading the create page, it should show the token selection stage", - goldenFileName: "create_page_initial_stage", (tester) async { - await tester.pumpDeviceBuilder(await goldenBuilder()); - await tester.pumpAndSettle(); - }); + zGoldenTest( + "When loading the create page, it should show the token selection stage", + goldenFileName: "create_page_initial_stage", + (tester) async { + await tester.pumpDeviceBuilder(await goldenBuilder()); + await tester.pumpAndSettle(); + }, + ); } diff --git a/test/app/create/deposit/deposit_cubit_test.dart b/test/app/create/deposit/deposit_cubit_test.dart index 2ec9345..b50c1f7 100644 --- a/test/app/create/deposit/deposit_cubit_test.dart +++ b/test/app/create/deposit/deposit_cubit_test.dart @@ -9,9 +9,9 @@ import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/deposit_cubit.dart'; import 'package:zup_app/core/cache.dart'; import 'package:zup_app/core/dtos/deposit_page_arguments_dto.dart'; import 'package:zup_app/core/dtos/deposit_settings_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pools_search_result_dto.dart'; import 'package:zup_app/core/dtos/pool_search_settings_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; -import 'package:zup_app/core/dtos/yields_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/pool_service.dart'; import 'package:zup_app/core/repositories/yield_repository.dart'; @@ -38,7 +38,7 @@ void main() { registerFallbackValue(DepositSettingsDto.fixture()); registerFallbackValue(AppNetworks.sepolia); registerFallbackValue(PoolSearchSettingsDto.fixture()); - registerFallbackValue(YieldDto.fixture()); + registerFallbackValue(LiquidityPoolDto.fixture()); poolService = PoolServiceMock(); yieldRepository = YieldRepositoryMock(); @@ -51,7 +51,7 @@ void main() { when( () => navigator.currentPageArguments, - ).thenReturn(const DepositPageArgumentsDto().copyWith(yieldPool: YieldDto.fixture()).toJson()); + ).thenReturn(const DepositPageArgumentsDto().copyWith(yieldPool: LiquidityPoolDto.fixture()).toJson()); sut = DepositCubit(yieldRepository, zupSingletonCache, wallet, cache, poolService, navigator); @@ -66,7 +66,7 @@ void main() { group1Id: any(named: "group1Id"), testnetMode: any(named: "testnetMode"), ), - ).thenAnswer((_) async => YieldsDto.fixture()); + ).thenAnswer((_) async => LiquidityPoolsSearchResultDto.fixture()); when(() => cache.getPoolSearchSettings()).thenReturn(PoolSearchSettingsDto.fixture()); when( @@ -353,7 +353,7 @@ void main() { """When calling 'fetchCurrentPoolInfo', after fetching the pool data from the repository, it should get the pool sqrt price from the pool service, and emit the new sqrt price gotten""", () async { - final pool = YieldDto.fixture(); + final pool = LiquidityPoolDto.fixture(); final expectedSqrtPriceX96 = BigInt.from(126128912198); when(() => poolService.getSqrtPriceX96(pool)).thenAnswer((_) async => expectedSqrtPriceX96); @@ -381,7 +381,7 @@ void main() { it should get the pool sqrt price from the pool service, and assign it to the latest poolSqrtPriceX96 variable""", () async { - final pool = YieldDto.fixture(); + final pool = LiquidityPoolDto.fixture(); final expectedSqrtPriceX96 = BigInt.from(1111); when(() => poolService.getSqrtPriceX96(pool)).thenAnswer((_) async => expectedSqrtPriceX96); @@ -407,7 +407,7 @@ void main() { """When calling 'fetchCurrentPoolInfo', after fetching the pool data from the repository, it should emit the success state with the pool data""", () async { - final pool = YieldDto.fixture().copyWith(poolAddress: "pool for testing emit success"); + final pool = LiquidityPoolDto.fixture().copyWith(poolAddress: "pool for testing emit success"); when(() => navigator.getQueryParam(DepositRouteParamsNames().network)).thenReturn("sepolia"); when(() => navigator.getIdFromPath).thenReturn("0xbas"); @@ -458,7 +458,7 @@ void main() { """When instaciating the cubit, and there is a pool coming from the arguments, it should assign it to the yieldpool variable and not fetch the pool info from the repository""", () { - final pool = YieldDto.fixture().copyWith(poolAddress: "jajajajaja"); + final pool = LiquidityPoolDto.fixture().copyWith(poolAddress: "jajajajaja"); when(() => navigator.currentPageArguments).thenReturn(DepositPageArgumentsDto(yieldPool: pool).toJson()); @@ -481,7 +481,7 @@ void main() { it should emit a new pool sqrt price got from the yield dto""", () async { final expectedSqrtPriceX96 = BigInt.from(989998899); - final pool = YieldDto.fixture().copyWith( + final pool = LiquidityPoolDto.fixture().copyWith( poolAddress: "jajajajaja", latestSqrtPriceX96: expectedSqrtPriceX96.toString(), ); @@ -500,7 +500,7 @@ void main() { it should assign the pool sqrt price to the latest pool sqrt price variable""", () async { final expectedSqrtPriceX96 = BigInt.from(5545529927344); - final pool = YieldDto.fixture().copyWith( + final pool = LiquidityPoolDto.fixture().copyWith( poolAddress: "jajajajaja", latestSqrtPriceX96: expectedSqrtPriceX96.toString(), ); @@ -517,7 +517,7 @@ void main() { """When instaciating the cubit, and there is a pool coming from the arguments, it should emit the success state passing the pool from the arguments""", () async { - final pool = YieldDto.fixture().copyWith(poolAddress: "someel cool pool idool"); + final pool = LiquidityPoolDto.fixture().copyWith(poolAddress: "someel cool pool idool"); when(() => navigator.currentPageArguments).thenReturn(DepositPageArgumentsDto(yieldPool: pool).toJson()); diff --git a/test/app/create/deposit/deposit_page_test.dart b/test/app/create/deposit/deposit_page_test.dart index 36992cb..59ffa26 100644 --- a/test/app/create/deposit/deposit_page_test.dart +++ b/test/app/create/deposit/deposit_page_test.dart @@ -17,12 +17,12 @@ import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/deposit_page.dart'; import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/widgets/preview_deposit_modal/preview_deposit_modal.dart'; import 'package:zup_app/core/cache.dart'; import 'package:zup_app/core/dtos/deposit_settings_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pools_search_result_dto.dart'; import 'package:zup_app/core/dtos/pool_search_settings_dto.dart'; import 'package:zup_app/core/dtos/token_price_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; -import 'package:zup_app/core/dtos/yields_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/core/pool_service.dart'; import 'package:zup_app/core/repositories/tokens_repository.dart'; @@ -31,8 +31,8 @@ import 'package:zup_app/core/zup_analytics.dart'; import 'package:zup_app/core/zup_links.dart'; import 'package:zup_app/core/zup_navigator.dart'; import 'package:zup_app/core/zup_route_params_names.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; import 'package:zup_core/zup_core.dart'; +import 'package:zup_ui_kit/zup_network_image.dart'; import '../../../golden_config.dart'; import '../../../mocks.dart'; @@ -85,7 +85,7 @@ void main() { inject.registerFactory>(() => GlobalKey()); inject.registerFactory(() => navigator); inject.registerFactory(() => wallet); - inject.registerFactory(() => mockZupCachedImage()); + inject.registerFactory(() => mockZupNetworkImage()); inject.registerFactory(() => appCubit); inject.registerFactory(() => ZupSingletonCache.shared); inject.registerFactory>(() => GlobalKey()); @@ -112,9 +112,9 @@ void main() { when(() => cubit.saveDepositSettings(any(), any())).thenAnswer((_) async => ()); when(() => cubit.depositSettings).thenReturn(DepositSettingsDto.fixture()); when(() => cubit.poolSearchSettings).thenReturn(PoolSearchSettingsDto.fixture()); - when(() => cubit.yieldPool).thenReturn(YieldDto.fixture()); + when(() => cubit.yieldPool).thenReturn(LiquidityPoolDto.fixture()); when(() => navigator.getQueryParam(DepositRouteParamsNames().network)).thenReturn(AppNetworks.mainnet.name); - when(() => navigator.getQueryParam(DepositRouteParamsNames().timeframe)).thenReturn(YieldTimeFrame.day.name); + when(() => navigator.getQueryParam(DepositRouteParamsNames().timeframe)).thenReturn(PoolDataTimeframe.day.name); when(() => navigator.getQueryParam(DepositRouteParamsNames().parseWrappedToNative)).thenReturn(true.toString()); when(() => navigator.canBack(any())).thenReturn(false); }); @@ -185,7 +185,7 @@ void main() { tester, ) async { await tester.runAsync(() async { - final pool = YieldDto.fixture(); + final pool = LiquidityPoolDto.fixture(); when(() => cubit.state).thenReturn(DepositState.success(pool)); @@ -205,7 +205,7 @@ void main() { () => cubit.depositSettings, ).thenReturn(const DepositSettingsDto(deadlineMinutes: 10, maxSlippage: DepositSettingsDto.defaultMaxSlippage)); - when(() => cubit.state).thenReturn(DepositState.success(YieldDto.fixture())); + when(() => cubit.state).thenReturn(DepositState.success(LiquidityPoolDto.fixture())); await tester.pumpDeviceBuilder(await goldenBuilder(isMobile: true)); await tester.pumpAndSettle(); @@ -219,7 +219,7 @@ void main() { zGoldenTest("When clicking back in the success state, it should navigate to the choose tokens page", (tester) async { when(() => navigator.navigateToNewPosition()).thenAnswer((_) async {}); - when(() => cubit.state).thenReturn(DepositState.success(YieldDto.fixture())); + when(() => cubit.state).thenReturn(DepositState.success(LiquidityPoolDto.fixture())); await tester.runAsync(() async { await tester.pumpDeviceBuilder(await goldenBuilder()); @@ -238,7 +238,7 @@ void main() { (tester) async { when(() => navigator.canBack(any())).thenReturn(true); when(() => navigator.navigateToNewPosition()).thenAnswer((_) async {}); - when(() => cubit.state).thenReturn(DepositState.success(YieldDto.fixture())); + when(() => cubit.state).thenReturn(DepositState.success(LiquidityPoolDto.fixture())); await tester.runAsync(() async { await tester.pumpDeviceBuilder(await goldenBuilder()); @@ -259,7 +259,7 @@ void main() { (tester) async { when(() => navigator.canBack(any())).thenReturn(true); when(() => navigator.navigateToNewPosition()).thenAnswer((_) async {}); - when(() => cubit.state).thenReturn(DepositState.success(YieldDto.fixture())); + when(() => cubit.state).thenReturn(DepositState.success(LiquidityPoolDto.fixture())); await tester.runAsync(() async { await tester.pumpDeviceBuilder(await goldenBuilder()); @@ -273,7 +273,7 @@ void main() { goldenFileName: "deposit_page_reverse_tokens", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -292,7 +292,7 @@ void main() { goldenFileName: "deposit_page_reverse_tokens_back", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -314,7 +314,7 @@ void main() { goldenFileName: "deposit_page_reverse_tokens_back", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -337,7 +337,7 @@ void main() { goldenFileName: "deposit_page_calculate_price", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -355,7 +355,7 @@ void main() { goldenFileName: "deposit_page_calculate_price_reversed", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -378,7 +378,7 @@ void main() { goldenFileName: "deposit_page_min_price_out_of_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -405,7 +405,7 @@ void main() { goldenFileName: "deposit_page_min_price_out_of_range_reversed_in_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsSqrtPriceX96 = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -433,7 +433,7 @@ void main() { goldenFileName: "deposit_page_min_price_out_of_range_reversed", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -458,7 +458,7 @@ void main() { goldenFileName: "deposit_page_max_price_less_than_min_price", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -489,7 +489,7 @@ void main() { goldenFileName: "deposit_page_max_price_out_of_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -516,7 +516,7 @@ void main() { goldenFileName: "deposit_page_max_price_set_to_infinity", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -550,7 +550,7 @@ void main() { goldenFileName: "deposit_page_min_price_set_to_full_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -575,7 +575,7 @@ void main() { goldenFileName: "deposit_page_5_percent_set_to_full_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -602,7 +602,7 @@ void main() { goldenFileName: "deposit_page_5_percent_set_to_full_range_reverse_tokens", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -632,7 +632,7 @@ void main() { goldenFileName: "deposit_page_set_5_percent_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -657,7 +657,7 @@ void main() { goldenFileName: "deposit_page_set_5_percent_range_reverse_tokens", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -683,7 +683,7 @@ void main() { goldenFileName: "deposit_page_set_20_percent_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -708,7 +708,7 @@ void main() { goldenFileName: "deposit_page_set_20_percent_range_reverse_tokens", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -734,7 +734,7 @@ void main() { goldenFileName: "deposit_page_set_50_percent_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -759,7 +759,7 @@ void main() { goldenFileName: "deposit_page_set_50_percent_range_reverse_tokens", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -784,7 +784,7 @@ void main() { goldenFileName: "deposit_page_max_price_set_to_full_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -811,7 +811,7 @@ void main() { goldenFileName: "deposit_page_set_percentage_range_then_type_max_price_reverse_tokens", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -841,7 +841,7 @@ void main() { goldenFileName: "deposit_page_set_percentage_range_then_type_min_price_reverse_tokens", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -870,7 +870,7 @@ void main() { goldenFileName: "deposit_page_min_and_max_price_set_to_full_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -898,7 +898,7 @@ void main() { goldenFileName: "deposit_page_invalid_range_deposit_section", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -931,7 +931,7 @@ void main() { goldenFileName: "deposit_page_input_base_token_amount", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsSqrtPriceX96 = BigInt.parse("5239001873626858491699987"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -956,7 +956,7 @@ void main() { goldenFileName: "deposit_page_input_quote_token_amount", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -982,7 +982,7 @@ void main() { goldenFileName: "deposit_page_input_base_token_amount_and_reverse", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1011,7 +1011,7 @@ void main() { goldenFileName: "deposit_page_input_quote_token_amount_and_reverse", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1038,7 +1038,7 @@ void main() { goldenFileName: "deposit_page_input_base_token_amount_reversed", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1065,7 +1065,7 @@ void main() { goldenFileName: "deposit_page_input_quote_token_amount_reversed", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1094,7 +1094,7 @@ void main() { goldenFileName: "deposit_page_input_base_token_amount_and_reverse_back", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1126,7 +1126,7 @@ void main() { goldenFileName: "deposit_page_input_quote_token_amount_and_reverse_back", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1156,7 +1156,7 @@ void main() { goldenFileName: "deposit_page_input_base_token_amount_and_change_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1192,7 +1192,7 @@ void main() { goldenFileName: "deposit_page_input_quote_token_amount_and_change_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1228,7 +1228,7 @@ void main() { goldenFileName: "deposit_page_input_base_token_amount_reverse_tokens_and_change_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1266,7 +1266,7 @@ void main() { goldenFileName: "deposit_page_input_quote_token_amount_reverse_tokens_and_change_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1305,7 +1305,7 @@ void main() { goldenFileName: "deposit_page_input_range_then_input_base_token_amount", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1341,7 +1341,7 @@ void main() { goldenFileName: "deposit_page_input_range_then_input_quote_token_amount", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1376,7 +1376,7 @@ void main() { goldenFileName: "deposit_page_input_range_then_reverse_tokens_then_input_base_token_amount", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1418,7 +1418,7 @@ void main() { goldenFileName: "deposit_page_input_range_then_reverse_tokens_then_input_quote_token_amount", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1460,7 +1460,7 @@ void main() { goldenFileName: "deposit_page_input_base_token_amount_then_set_max_price_out_of_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1494,7 +1494,7 @@ void main() { goldenFileName: "deposit_page_input_quote_token_amount_then_set_min_price_out_of_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1525,7 +1525,7 @@ void main() { goldenFileName: "deposit_page_input_base_token_amount_then_reverse_tokens_then_set_max_price_out_of_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1562,7 +1562,7 @@ void main() { goldenFileName: "deposit_page_input_quote_token_amount_then_reverse_tokens_then_set_min_price_out_of_range", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); @@ -1595,7 +1595,7 @@ void main() { goldenFileName: "deposit_page_not_connected", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => wallet.signer).thenReturn(null); @@ -1621,7 +1621,7 @@ void main() { goldenFileName: "deposit_page_not_connected_deposit_button_click", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); when(() => wallet.signer).thenReturn(null); @@ -1647,7 +1647,7 @@ void main() { goldenFileName: "deposit_page_no_amount_deposit_button", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); final signer = SignerMock(); @@ -1676,7 +1676,7 @@ void main() { goldenFileName: "deposit_page_not_enough_base_token_balance_deposit_button", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); final signer = SignerMock(); @@ -1708,7 +1708,7 @@ void main() { goldenFileName: "deposit_page_not_enough_quote_token_balance_deposit_button", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); final signer = SignerMock(); @@ -1716,16 +1716,10 @@ void main() { when(() => wallet.signerStream).thenAnswer((_) => Stream.value(signer)); when( - () => cubit.getWalletTokenAmount( - selectedYield.token0.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(32567352673)); when( - () => cubit.getWalletTokenAmount( - selectedYield.token1.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(0)); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -1749,7 +1743,7 @@ void main() { goldenFileName: "deposit_page_not_enough_base_token_balance_deposit_button_after_connecting", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); final signerStreamController = StreamController.broadcast(); final signer = SignerMock(); @@ -1757,16 +1751,10 @@ void main() { when(() => wallet.signer).thenReturn(null); when(() => wallet.signerStream).thenAnswer((_) => signerStreamController.stream); when( - () => cubit.getWalletTokenAmount( - selectedYield.token0.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(0)); when( - () => cubit.getWalletTokenAmount( - selectedYield.token1.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(0)); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -1793,7 +1781,7 @@ void main() { goldenFileName: "deposit_page_not_enough_quote_token_balance_deposit_button_after_connecting", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); final signerStreamController = StreamController.broadcast(); final signer = SignerMock(); @@ -1801,16 +1789,10 @@ void main() { when(() => wallet.signer).thenReturn(null); when(() => wallet.signerStream).thenAnswer((_) => signerStreamController.stream); when( - () => cubit.getWalletTokenAmount( - selectedYield.token0.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(347537253)); when( - () => cubit.getWalletTokenAmount( - selectedYield.token1.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(0)); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -1837,7 +1819,7 @@ void main() { goldenFileName: "deposit_page_enough_balance_deposit_button", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); final signer = SignerMock(); @@ -1845,16 +1827,10 @@ void main() { when(() => wallet.signer).thenReturn(signer); when(() => wallet.signerStream).thenAnswer((_) => Stream.value(signer)); when( - () => cubit.getWalletTokenAmount( - selectedYield.token0.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(EthereumConstants.uint256Max.toDouble())); when( - () => cubit.getWalletTokenAmount( - selectedYield.token1.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(32576352673)); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -1879,7 +1855,7 @@ void main() { goldenFileName: "deposit_page_min_range_out_of_range_deposit_button", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); final signer = SignerMock(); @@ -1887,16 +1863,10 @@ void main() { when(() => wallet.signer).thenReturn(signer); when(() => wallet.signerStream).thenAnswer((_) => Stream.value(signer)); when( - () => cubit.getWalletTokenAmount( - selectedYield.token0.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(347537253)); when( - () => cubit.getWalletTokenAmount( - selectedYield.token1.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(0)); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -1923,7 +1893,7 @@ void main() { goldenFileName: "deposit_page_max_range_out_of_range_deposit_button", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); final signer = SignerMock(); @@ -1931,16 +1901,10 @@ void main() { when(() => wallet.signer).thenReturn(signer); when(() => wallet.signerStream).thenAnswer((_) => Stream.value(signer)); when( - () => cubit.getWalletTokenAmount( - selectedYield.token0.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(0)); when( - () => cubit.getWalletTokenAmount( - selectedYield.token1.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(3237526)); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -1972,7 +1936,7 @@ void main() { goldenFileName: "deposit_page_preview_modal", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsTick = BigInt.parse("79121973566864535878904"); final signer = SignerMock(); @@ -1980,16 +1944,10 @@ void main() { when(() => wallet.signer).thenReturn(signer); when(() => wallet.signerStream).thenAnswer((_) => Stream.value(signer)); when( - () => cubit.getWalletTokenAmount( - selectedYield.token0.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(347537253)); when( - () => cubit.getWalletTokenAmount( - selectedYield.token1.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(32576352673)); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -2015,7 +1973,7 @@ void main() { goldenFileName: "deposit_page_quote_token_input_loading", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -2039,7 +1997,7 @@ void main() { goldenFileName: "deposit_page_base_token_input_loading", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -2064,7 +2022,7 @@ void main() { goldenFileName: "deposit_page_quote_token_input_enabled_after_loading", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -2089,7 +2047,7 @@ void main() { goldenFileName: "deposit_page_base_token_input_enabled_after_loading", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); when(() => cubit.yieldPool).thenReturn(selectedYield); @@ -2116,7 +2074,7 @@ void main() { const expectedDeadlineCallback = Duration(minutes: 21); when(() => cubit.saveDepositSettings(any(), any())).thenAnswer((_) async => () {}); - when(() => cubit.state).thenReturn(DepositState.success(YieldDto.fixture())); + when(() => cubit.state).thenReturn(DepositState.success(LiquidityPoolDto.fixture())); await tester.runAsync(() async { await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); @@ -2142,7 +2100,7 @@ void main() { goldenFileName: "deposit_page_deposit_settings_button_slippage_title", (tester) async { when(() => cubit.saveDepositSettings(any(), any())).thenAnswer((_) async => () {}); - when(() => cubit.state).thenReturn(DepositState.success(YieldDto.fixture())); + when(() => cubit.state).thenReturn(DepositState.success(LiquidityPoolDto.fixture())); await tester.runAsync(() async { await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); @@ -2161,7 +2119,7 @@ void main() { goldenFileName: "deposit_page_deposit_settings_button_orange", (tester) async { when(() => cubit.saveDepositSettings(any(), any())).thenAnswer((_) async => () {}); - when(() => cubit.state).thenReturn(DepositState.success(YieldDto.fixture())); + when(() => cubit.state).thenReturn(DepositState.success(LiquidityPoolDto.fixture())); await tester.runAsync(() async { await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); @@ -2181,7 +2139,7 @@ void main() { goldenFileName: "deposit_page_deposit_settings_button_zup_purple_gray", (tester) async { when(() => cubit.saveDepositSettings(any(), any())).thenAnswer((_) async => () {}); - when(() => cubit.state).thenReturn(DepositState.success(YieldDto.fixture())); + when(() => cubit.state).thenReturn(DepositState.success(LiquidityPoolDto.fixture())); await tester.runAsync(() async { await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); @@ -2202,7 +2160,7 @@ void main() { goldenFileName: "deposit_page_deposit_settings_button_red", (tester) async { when(() => cubit.saveDepositSettings(any(), any())).thenAnswer((_) async => () {}); - when(() => cubit.state).thenReturn(DepositState.success(YieldDto.fixture())); + when(() => cubit.state).thenReturn(DepositState.success(LiquidityPoolDto.fixture())); await tester.runAsync(() async { await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); @@ -2224,7 +2182,7 @@ void main() { const expectedDeadlineCallback = Duration(minutes: 21); when(() => cubit.saveDepositSettings(any(), any())).thenAnswer((_) async => () {}); - when(() => cubit.state).thenReturn(DepositState.success(YieldDto.fixture())); + when(() => cubit.state).thenReturn(DepositState.success(LiquidityPoolDto.fixture())); await tester.runAsync(() async { await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); @@ -2251,7 +2209,7 @@ void main() { (tester) async { const expectedDepositSettings = DepositSettingsDto(maxSlippage: 32.1, deadlineMinutes: 98); when(() => cubit.saveDepositSettings(any(), any())).thenAnswer((_) async => () {}); - when(() => cubit.state).thenReturn(DepositState.success(YieldDto.fixture())); + when(() => cubit.state).thenReturn(DepositState.success(LiquidityPoolDto.fixture())); when(() => cubit.depositSettings).thenReturn(expectedDepositSettings); await tester.runAsync(() async { @@ -2268,7 +2226,7 @@ void main() { goldenFileName: "deposit_page_deposit_settings_dropdown_reopening", (tester) async { when(() => cubit.saveDepositSettings(any(), any())).thenAnswer((_) async => () {}); - when(() => cubit.state).thenReturn(DepositState.success(YieldDto.fixture())); + when(() => cubit.state).thenReturn(DepositState.success(LiquidityPoolDto.fixture())); await tester.runAsync(() async { await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); await tester.tap(find.byKey(const Key("deposit-settings-button"))); @@ -2305,7 +2263,7 @@ void main() { const expectedDeadline = Duration(minutes: 76); await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsSqrtPriceX96 = BigInt.parse("5240418162556390792557189"); final signer = SignerMock(); @@ -2369,7 +2327,7 @@ void main() { goldenFileName: "deposit_page_pool_tick_update_deposit_amount", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().poolsSortedBy24hYield.first; + final selectedYield = LiquidityPoolsSearchResultDto.fixture().poolsSortedBy24hYield.first; final currentPriceAsSqrtPriceX96 = BigInt.parse("79121973566864535878904"); final nextPriceAsSqrtPriceX96 = BigInt.parse("5240418162556390792557189"); final poolSqrtPriceX96StreamController = StreamController.broadcast(); @@ -2379,16 +2337,10 @@ void main() { when(() => wallet.signer).thenReturn(signer); when(() => wallet.signerStream).thenAnswer((_) => Stream.value(signer)); when( - () => cubit.getWalletTokenAmount( - selectedYield.token0.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(347537253)); when( - () => cubit.getWalletTokenAmount( - selectedYield.token1.addresses[selectedYield.network.chainId]!, - network: any(named: "network"), - ), + () => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network")), ).thenAnswer((_) => Future.value(32576352673)); when(() => cubit.state).thenReturn(DepositState.success(selectedYield)); diff --git a/test/app/create/deposit/goldens/deposit_page_5_percent_set_to_full_range.png b/test/app/create/deposit/goldens/deposit_page_5_percent_set_to_full_range.png index e6a2a99..b1cf1e6 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_5_percent_set_to_full_range.png and b/test/app/create/deposit/goldens/deposit_page_5_percent_set_to_full_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_5_percent_set_to_full_range_reverse_tokens.png b/test/app/create/deposit/goldens/deposit_page_5_percent_set_to_full_range_reverse_tokens.png index a410378..0805ca8 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_5_percent_set_to_full_range_reverse_tokens.png and b/test/app/create/deposit/goldens/deposit_page_5_percent_set_to_full_range_reverse_tokens.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_back_button_can_back_true.png b/test/app/create/deposit/goldens/deposit_page_back_button_can_back_true.png index 8d4b834..d94992e 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_back_button_can_back_true.png and b/test/app/create/deposit/goldens/deposit_page_back_button_can_back_true.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_base_token_input_enabled_after_loading.png b/test/app/create/deposit/goldens/deposit_page_base_token_input_enabled_after_loading.png index d551d10..5c1d4cb 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_base_token_input_enabled_after_loading.png and b/test/app/create/deposit/goldens/deposit_page_base_token_input_enabled_after_loading.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_base_token_input_loading.png b/test/app/create/deposit/goldens/deposit_page_base_token_input_loading.png index 0d33e38..0b0d5ec 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_base_token_input_loading.png and b/test/app/create/deposit/goldens/deposit_page_base_token_input_loading.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_calculate_price.png b/test/app/create/deposit/goldens/deposit_page_calculate_price.png index 5367564..ab85d15 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_calculate_price.png and b/test/app/create/deposit/goldens/deposit_page_calculate_price.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_calculate_price_reversed.png b/test/app/create/deposit/goldens/deposit_page_calculate_price_reversed.png index a410378..0805ca8 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_calculate_price_reversed.png and b/test/app/create/deposit/goldens/deposit_page_calculate_price_reversed.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_orange.png b/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_orange.png index 0a6f85c..3acb717 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_orange.png and b/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_orange.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_red.png b/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_red.png index c7557fe..eb64c61 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_red.png and b/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_red.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_slippage_title.png b/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_slippage_title.png index 90238a8..c7696c6 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_slippage_title.png and b/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_slippage_title.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_zup_purple_gray.png b/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_zup_purple_gray.png index 35fed96..e0a7383 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_zup_purple_gray.png and b/test/app/create/deposit/goldens/deposit_page_deposit_settings_button_zup_purple_gray.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_deposit_settings_dropdown.png b/test/app/create/deposit/goldens/deposit_page_deposit_settings_dropdown.png index 53f8a60..8af8a90 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_deposit_settings_dropdown.png and b/test/app/create/deposit/goldens/deposit_page_deposit_settings_dropdown.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_deposit_settings_dropdown_reopening.png b/test/app/create/deposit/goldens/deposit_page_deposit_settings_dropdown_reopening.png index 555b0b6..5f0e03c 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_deposit_settings_dropdown_reopening.png and b/test/app/create/deposit/goldens/deposit_page_deposit_settings_dropdown_reopening.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_enough_balance_deposit_button.png b/test/app/create/deposit/goldens/deposit_page_enough_balance_deposit_button.png index 0e5fe6c..0812158 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_enough_balance_deposit_button.png and b/test/app/create/deposit/goldens/deposit_page_enough_balance_deposit_button.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount.png b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount.png index 39ed0dd..d7d44f2 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount.png and b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_and_change_range.png b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_and_change_range.png index de8f9c9..9a63db3 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_and_change_range.png and b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_and_change_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_and_reverse.png b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_and_reverse.png index 6c3404b..26d9d29 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_and_reverse.png and b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_and_reverse.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_and_reverse_back.png b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_and_reverse_back.png index 54eb1d4..09f624e 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_and_reverse_back.png and b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_and_reverse_back.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_reverse_tokens_and_change_range.png b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_reverse_tokens_and_change_range.png index fd965f0..ce89606 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_reverse_tokens_and_change_range.png and b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_reverse_tokens_and_change_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_reversed.png b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_reversed.png index df7bc8d..90d8278 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_reversed.png and b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_reversed.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_then_reverse_tokens_then_set_max_price_out_of_range.png b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_then_reverse_tokens_then_set_max_price_out_of_range.png index c6ff04f..f571f8a 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_then_reverse_tokens_then_set_max_price_out_of_range.png and b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_then_reverse_tokens_then_set_max_price_out_of_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_then_set_max_price_out_of_range.png b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_then_set_max_price_out_of_range.png index c00e6df..090f4ef 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_then_set_max_price_out_of_range.png and b/test/app/create/deposit/goldens/deposit_page_input_base_token_amount_then_set_max_price_out_of_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount.png b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount.png index 68b6399..e0537dd 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount.png and b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_and_change_range.png b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_and_change_range.png index ce2631c..6f3b18a 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_and_change_range.png and b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_and_change_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_and_reverse.png b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_and_reverse.png index dcc0f21..fa9e91a 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_and_reverse.png and b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_and_reverse.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_and_reverse_back.png b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_and_reverse_back.png index 6b9250d..8eabd68 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_and_reverse_back.png and b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_and_reverse_back.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_reverse_tokens_and_change_range.png b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_reverse_tokens_and_change_range.png index 5cc2c6b..ac4b822 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_reverse_tokens_and_change_range.png and b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_reverse_tokens_and_change_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_reversed.png b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_reversed.png index 3e1d11c..bcefe20 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_reversed.png and b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_reversed.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_then_reverse_tokens_then_set_min_price_out_of_range.png b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_then_reverse_tokens_then_set_min_price_out_of_range.png index f34659a..7901f1b 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_then_reverse_tokens_then_set_min_price_out_of_range.png and b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_then_reverse_tokens_then_set_min_price_out_of_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_then_set_min_price_out_of_range.png b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_then_set_min_price_out_of_range.png index bbe1e3e..94e2014 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_then_set_min_price_out_of_range.png and b/test/app/create/deposit/goldens/deposit_page_input_quote_token_amount_then_set_min_price_out_of_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_range_then_input_base_token_amount.png b/test/app/create/deposit/goldens/deposit_page_input_range_then_input_base_token_amount.png index 4795d19..2fdefb7 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_range_then_input_base_token_amount.png and b/test/app/create/deposit/goldens/deposit_page_input_range_then_input_base_token_amount.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_range_then_input_quote_token_amount.png b/test/app/create/deposit/goldens/deposit_page_input_range_then_input_quote_token_amount.png index dab7049..7945905 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_range_then_input_quote_token_amount.png and b/test/app/create/deposit/goldens/deposit_page_input_range_then_input_quote_token_amount.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_range_then_reverse_tokens_then_input_base_token_amount.png b/test/app/create/deposit/goldens/deposit_page_input_range_then_reverse_tokens_then_input_base_token_amount.png index c439d98..7fdf957 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_range_then_reverse_tokens_then_input_base_token_amount.png and b/test/app/create/deposit/goldens/deposit_page_input_range_then_reverse_tokens_then_input_base_token_amount.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_input_range_then_reverse_tokens_then_input_quote_token_amount.png b/test/app/create/deposit/goldens/deposit_page_input_range_then_reverse_tokens_then_input_quote_token_amount.png index 313612e..a8cd78c 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_input_range_then_reverse_tokens_then_input_quote_token_amount.png and b/test/app/create/deposit/goldens/deposit_page_input_range_then_reverse_tokens_then_input_quote_token_amount.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_invalid_range_deposit_section.png b/test/app/create/deposit/goldens/deposit_page_invalid_range_deposit_section.png index 9eb682a..b7910fe 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_invalid_range_deposit_section.png and b/test/app/create/deposit/goldens/deposit_page_invalid_range_deposit_section.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_loading.png b/test/app/create/deposit/goldens/deposit_page_loading.png index 5d8107a..ef2a586 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_loading.png and b/test/app/create/deposit/goldens/deposit_page_loading.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_max_price_less_than_min_price.png b/test/app/create/deposit/goldens/deposit_page_max_price_less_than_min_price.png index 00af807..4b71210 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_max_price_less_than_min_price.png and b/test/app/create/deposit/goldens/deposit_page_max_price_less_than_min_price.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_max_price_out_of_range.png b/test/app/create/deposit/goldens/deposit_page_max_price_out_of_range.png index 8c6dcb9..ad41f18 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_max_price_out_of_range.png and b/test/app/create/deposit/goldens/deposit_page_max_price_out_of_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_max_price_set_to_full_range.png b/test/app/create/deposit/goldens/deposit_page_max_price_set_to_full_range.png index 22be73f..9f760ee 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_max_price_set_to_full_range.png and b/test/app/create/deposit/goldens/deposit_page_max_price_set_to_full_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_max_price_set_to_infinity.png b/test/app/create/deposit/goldens/deposit_page_max_price_set_to_infinity.png index a68718b..3131443 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_max_price_set_to_infinity.png and b/test/app/create/deposit/goldens/deposit_page_max_price_set_to_infinity.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_max_range_out_of_range_deposit_button.png b/test/app/create/deposit/goldens/deposit_page_max_range_out_of_range_deposit_button.png index cb4871f..0e8e67e 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_max_range_out_of_range_deposit_button.png and b/test/app/create/deposit/goldens/deposit_page_max_range_out_of_range_deposit_button.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_min_and_max_price_set_to_full_range.png b/test/app/create/deposit/goldens/deposit_page_min_and_max_price_set_to_full_range.png index 22be73f..9f760ee 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_min_and_max_price_set_to_full_range.png and b/test/app/create/deposit/goldens/deposit_page_min_and_max_price_set_to_full_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_min_price_out_of_range.png b/test/app/create/deposit/goldens/deposit_page_min_price_out_of_range.png index 36a8837..f5e8f9c 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_min_price_out_of_range.png and b/test/app/create/deposit/goldens/deposit_page_min_price_out_of_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_min_price_out_of_range_reversed.png b/test/app/create/deposit/goldens/deposit_page_min_price_out_of_range_reversed.png index fde882a..25e2015 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_min_price_out_of_range_reversed.png and b/test/app/create/deposit/goldens/deposit_page_min_price_out_of_range_reversed.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_min_price_out_of_range_reversed_in_range.png b/test/app/create/deposit/goldens/deposit_page_min_price_out_of_range_reversed_in_range.png index 9614783..c6ef023 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_min_price_out_of_range_reversed_in_range.png and b/test/app/create/deposit/goldens/deposit_page_min_price_out_of_range_reversed_in_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_min_price_set_to_full_range.png b/test/app/create/deposit/goldens/deposit_page_min_price_set_to_full_range.png index 22be73f..9f760ee 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_min_price_set_to_full_range.png and b/test/app/create/deposit/goldens/deposit_page_min_price_set_to_full_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_min_range_out_of_range_deposit_button.png b/test/app/create/deposit/goldens/deposit_page_min_range_out_of_range_deposit_button.png index 19dcf1e..abd9cc5 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_min_range_out_of_range_deposit_button.png and b/test/app/create/deposit/goldens/deposit_page_min_range_out_of_range_deposit_button.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_no_amount_deposit_button.png b/test/app/create/deposit/goldens/deposit_page_no_amount_deposit_button.png index b285113..86b066c 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_no_amount_deposit_button.png and b/test/app/create/deposit/goldens/deposit_page_no_amount_deposit_button.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_not_connected.png b/test/app/create/deposit/goldens/deposit_page_not_connected.png index 5a3d219..8be69a7 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_not_connected.png and b/test/app/create/deposit/goldens/deposit_page_not_connected.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_not_connected_deposit_button_click.png b/test/app/create/deposit/goldens/deposit_page_not_connected_deposit_button_click.png index 7c210bc..f36955a 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_not_connected_deposit_button_click.png and b/test/app/create/deposit/goldens/deposit_page_not_connected_deposit_button_click.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_not_enough_base_token_balance_deposit_button.png b/test/app/create/deposit/goldens/deposit_page_not_enough_base_token_balance_deposit_button.png index 8973867..63e5fe7 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_not_enough_base_token_balance_deposit_button.png and b/test/app/create/deposit/goldens/deposit_page_not_enough_base_token_balance_deposit_button.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_not_enough_base_token_balance_deposit_button_after_connecting.png b/test/app/create/deposit/goldens/deposit_page_not_enough_base_token_balance_deposit_button_after_connecting.png index 3a99794..daf6df8 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_not_enough_base_token_balance_deposit_button_after_connecting.png and b/test/app/create/deposit/goldens/deposit_page_not_enough_base_token_balance_deposit_button_after_connecting.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_not_enough_quote_token_balance_deposit_button.png b/test/app/create/deposit/goldens/deposit_page_not_enough_quote_token_balance_deposit_button.png index 50cbc81..29f1fb5 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_not_enough_quote_token_balance_deposit_button.png and b/test/app/create/deposit/goldens/deposit_page_not_enough_quote_token_balance_deposit_button.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_not_enough_quote_token_balance_deposit_button_after_connecting.png b/test/app/create/deposit/goldens/deposit_page_not_enough_quote_token_balance_deposit_button_after_connecting.png index 50cbc81..29f1fb5 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_not_enough_quote_token_balance_deposit_button_after_connecting.png and b/test/app/create/deposit/goldens/deposit_page_not_enough_quote_token_balance_deposit_button_after_connecting.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_pool_tick_update_deposit_amount.png b/test/app/create/deposit/goldens/deposit_page_pool_tick_update_deposit_amount.png index 3db3179..5e2664e 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_pool_tick_update_deposit_amount.png and b/test/app/create/deposit/goldens/deposit_page_pool_tick_update_deposit_amount.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_preview_modal.png b/test/app/create/deposit/goldens/deposit_page_preview_modal.png index b0d44c8..a0a138d 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_preview_modal.png and b/test/app/create/deposit/goldens/deposit_page_preview_modal.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_quote_token_input_enabled_after_loading.png b/test/app/create/deposit/goldens/deposit_page_quote_token_input_enabled_after_loading.png index 0c8d51c..a90d3b7 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_quote_token_input_enabled_after_loading.png and b/test/app/create/deposit/goldens/deposit_page_quote_token_input_enabled_after_loading.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_quote_token_input_loading.png b/test/app/create/deposit/goldens/deposit_page_quote_token_input_loading.png index aeb152f..7a48f45 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_quote_token_input_loading.png and b/test/app/create/deposit/goldens/deposit_page_quote_token_input_loading.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_range_section_mobile.png b/test/app/create/deposit/goldens/deposit_page_range_section_mobile.png index f8df159..caa5869 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_range_section_mobile.png and b/test/app/create/deposit/goldens/deposit_page_range_section_mobile.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_reverse_tokens.png b/test/app/create/deposit/goldens/deposit_page_reverse_tokens.png index a410378..0805ca8 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_reverse_tokens.png and b/test/app/create/deposit/goldens/deposit_page_reverse_tokens.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_reverse_tokens_back.png b/test/app/create/deposit/goldens/deposit_page_reverse_tokens_back.png index e6a2a99..b1cf1e6 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_reverse_tokens_back.png and b/test/app/create/deposit/goldens/deposit_page_reverse_tokens_back.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_set_20_percent_range.png b/test/app/create/deposit/goldens/deposit_page_set_20_percent_range.png index 28179dd..2bcb7b5 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_set_20_percent_range.png and b/test/app/create/deposit/goldens/deposit_page_set_20_percent_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_set_20_percent_range_reverse_tokens.png b/test/app/create/deposit/goldens/deposit_page_set_20_percent_range_reverse_tokens.png index 0f8af3e..c2ad6de 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_set_20_percent_range_reverse_tokens.png and b/test/app/create/deposit/goldens/deposit_page_set_20_percent_range_reverse_tokens.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_set_50_percent_range.png b/test/app/create/deposit/goldens/deposit_page_set_50_percent_range.png index 121bf12..b24e008 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_set_50_percent_range.png and b/test/app/create/deposit/goldens/deposit_page_set_50_percent_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_set_50_percent_range_reverse_tokens.png b/test/app/create/deposit/goldens/deposit_page_set_50_percent_range_reverse_tokens.png index b9cf55f..b8af1e2 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_set_50_percent_range_reverse_tokens.png and b/test/app/create/deposit/goldens/deposit_page_set_50_percent_range_reverse_tokens.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_set_5_percent_range.png b/test/app/create/deposit/goldens/deposit_page_set_5_percent_range.png index 0e06985..483595c 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_set_5_percent_range.png and b/test/app/create/deposit/goldens/deposit_page_set_5_percent_range.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_set_5_percent_range_reverse_tokens.png b/test/app/create/deposit/goldens/deposit_page_set_5_percent_range_reverse_tokens.png index 2bedefc..1006af4 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_set_5_percent_range_reverse_tokens.png and b/test/app/create/deposit/goldens/deposit_page_set_5_percent_range_reverse_tokens.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_set_percentage_range_then_type_max_price_reverse_tokens.png b/test/app/create/deposit/goldens/deposit_page_set_percentage_range_then_type_max_price_reverse_tokens.png index 434612d..cea2b47 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_set_percentage_range_then_type_max_price_reverse_tokens.png and b/test/app/create/deposit/goldens/deposit_page_set_percentage_range_then_type_max_price_reverse_tokens.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_set_percentage_range_then_type_min_price_reverse_tokens.png b/test/app/create/deposit/goldens/deposit_page_set_percentage_range_then_type_min_price_reverse_tokens.png index 9fff2d3..f5631de 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_set_percentage_range_then_type_min_price_reverse_tokens.png and b/test/app/create/deposit/goldens/deposit_page_set_percentage_range_then_type_min_price_reverse_tokens.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_success.png b/test/app/create/deposit/goldens/deposit_page_success.png index 2ff0cc5..392bc3e 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_success.png and b/test/app/create/deposit/goldens/deposit_page_success.png differ diff --git a/test/app/create/deposit/widgets/deposit_settings_dropdown_child_test.dart b/test/app/create/deposit/widgets/deposit_settings_dropdown_child_test.dart index e3cb4a3..b383561 100644 --- a/test/app/create/deposit/widgets/deposit_settings_dropdown_child_test.dart +++ b/test/app/create/deposit/widgets/deposit_settings_dropdown_child_test.dart @@ -5,7 +5,7 @@ import 'package:url_launcher_platform_interface/url_launcher_platform_interface. import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/widgets/deposit_settings_dropdown_child.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/core/slippage.dart'; -import 'package:zup_core/zup_core.dart'; +import 'package:zup_core/test_utils.dart'; import '../../../../golden_config.dart'; import '../../../../mocks.dart'; diff --git a/test/app/create/deposit/widgets/deposit_success_modal_test.dart b/test/app/create/deposit/widgets/deposit_success_modal_test.dart index fe55ae2..4772911 100644 --- a/test/app/create/deposit/widgets/deposit_success_modal_test.dart +++ b/test/app/create/deposit/widgets/deposit_success_modal_test.dart @@ -5,10 +5,10 @@ import 'package:golden_toolkit/golden_toolkit.dart'; import 'package:mocktail/mocktail.dart'; import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/widgets/deposit_success_modal.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; import 'package:zup_app/core/dtos/protocol_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; import 'package:zup_app/core/injections.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; +import 'package:zup_ui_kit/zup_network_image.dart'; import '../../../../golden_config.dart'; import '../../../../mocks.dart'; @@ -21,7 +21,7 @@ void main() { confettiController = ConfettiControllerMock(); - inject.registerFactory(() => mockZupCachedImage()); + inject.registerFactory(() => mockZupNetworkImage()); inject.registerFactory( () => confettiController, instanceName: InjectInstanceNames.confettiController10s, @@ -33,14 +33,14 @@ void main() { tearDown(() => inject.reset()); - Future goldenBuilder({YieldDto? customYield, bool showAsBottomSheet = false}) async => + Future goldenBuilder({LiquidityPoolDto? customYield, bool showAsBottomSheet = false}) async => await goldenDeviceBuilder( Builder( builder: (context) { WidgetsBinding.instance.addPostFrameCallback((_) { DepositSuccessModal.show( context, - depositedYield: customYield ?? YieldDto.fixture().copyWith(), + depositedYield: customYield ?? LiquidityPoolDto.fixture().copyWith(), showAsBottomSheet: showAsBottomSheet, ); }); @@ -84,7 +84,7 @@ void main() { await tester.pumpDeviceBuilder( await goldenBuilder( - customYield: YieldDto.fixture().copyWith(protocol: ProtocolDto.fixture().copyWith(url: protocolUrl)), + customYield: LiquidityPoolDto.fixture().copyWith(protocol: ProtocolDto.fixture().copyWith(url: protocolUrl)), ), wrapper: GoldenConfig.localizationsWrapper(), ); diff --git a/test/app/create/deposit/widgets/goldens/deposit_success_modal.png b/test/app/create/deposit/widgets/goldens/deposit_success_modal.png index 319ad5e..3101bea 100644 Binary files a/test/app/create/deposit/widgets/goldens/deposit_success_modal.png and b/test/app/create/deposit/widgets/goldens/deposit_success_modal.png differ diff --git a/test/app/create/deposit/widgets/goldens/deposit_success_modal_bottom_sheet.png b/test/app/create/deposit/widgets/goldens/deposit_success_modal_bottom_sheet.png index bd41c02..50c6e0f 100644 Binary files a/test/app/create/deposit/widgets/goldens/deposit_success_modal_bottom_sheet.png and b/test/app/create/deposit/widgets/goldens/deposit_success_modal_bottom_sheet.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_decrease_price.png b/test/app/create/deposit/widgets/goldens/range_selector_decrease_price.png index e0b73b0..8002131 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_decrease_price.png and b/test/app/create/deposit/widgets/goldens/range_selector_decrease_price.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_error_state.png b/test/app/create/deposit/widgets/goldens/range_selector_error_state.png index bd324e9..cc0ddb7 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_error_state.png and b/test/app/create/deposit/widgets/goldens/range_selector_error_state.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_increase_price.png b/test/app/create/deposit/widgets/goldens/range_selector_increase_price.png index cd40b73..666ac60 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_increase_price.png and b/test/app/create/deposit/widgets/goldens/range_selector_increase_price.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_initial_price.png b/test/app/create/deposit/widgets/goldens/range_selector_initial_price.png index 37f94a0..23d192c 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_initial_price.png and b/test/app/create/deposit/widgets/goldens/range_selector_initial_price.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_decrease_price.png b/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_decrease_price.png index 94452da..ed01d4c 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_decrease_price.png and b/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_decrease_price.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_decrease_price_reversed.png b/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_decrease_price_reversed.png index 94452da..ed01d4c 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_decrease_price_reversed.png and b/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_decrease_price_reversed.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price.png b/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price.png index 2cc7b8a..e1e28e3 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price.png and b/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price_reversed.png b/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price_reversed.png index 2cc7b8a..e1e28e3 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price_reversed.png and b/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price_reversed.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_is_reversed_decrease_price.png b/test/app/create/deposit/widgets/goldens/range_selector_is_reversed_decrease_price.png index b7aa0a5..d8200f5 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_is_reversed_decrease_price.png and b/test/app/create/deposit/widgets/goldens/range_selector_is_reversed_decrease_price.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_is_reversed_increase_price.png b/test/app/create/deposit/widgets/goldens/range_selector_is_reversed_increase_price.png index acac6e5..d4c4548 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_is_reversed_increase_price.png and b/test/app/create/deposit/widgets/goldens/range_selector_is_reversed_increase_price.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_is_reversed_typed_price.png b/test/app/create/deposit/widgets/goldens/range_selector_is_reversed_typed_price.png index 604d02b..3c70730 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_is_reversed_typed_price.png and b/test/app/create/deposit/widgets/goldens/range_selector_is_reversed_typed_price.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_max_price.png b/test/app/create/deposit/widgets/goldens/range_selector_max_price.png index 6cac44d..21d40c5 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_max_price.png and b/test/app/create/deposit/widgets/goldens/range_selector_max_price.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_max_price_infinity.png b/test/app/create/deposit/widgets/goldens/range_selector_max_price_infinity.png index 9795605..e2ebb87 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_max_price_infinity.png and b/test/app/create/deposit/widgets/goldens/range_selector_max_price_infinity.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_min_price.png b/test/app/create/deposit/widgets/goldens/range_selector_min_price.png index 8d4178d..485c059 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_min_price.png and b/test/app/create/deposit/widgets/goldens/range_selector_min_price.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_min_price_infinity.png b/test/app/create/deposit/widgets/goldens/range_selector_min_price_infinity.png index 94452da..ed01d4c 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_min_price_infinity.png and b/test/app/create/deposit/widgets/goldens/range_selector_min_price_infinity.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_reversed.png b/test/app/create/deposit/widgets/goldens/range_selector_reversed.png index 8d4178d..485c059 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_reversed.png and b/test/app/create/deposit/widgets/goldens/range_selector_reversed.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_update_infinity_price_max_price.png b/test/app/create/deposit/widgets/goldens/range_selector_update_infinity_price_max_price.png index 9795605..e2ebb87 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_update_infinity_price_max_price.png and b/test/app/create/deposit/widgets/goldens/range_selector_update_infinity_price_max_price.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_update_infinity_price_min_price.png b/test/app/create/deposit/widgets/goldens/range_selector_update_infinity_price_min_price.png index 94452da..ed01d4c 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_update_infinity_price_min_price.png and b/test/app/create/deposit/widgets/goldens/range_selector_update_infinity_price_min_price.png differ diff --git a/test/app/create/deposit/widgets/goldens/range_selector_warning_state.png b/test/app/create/deposit/widgets/goldens/range_selector_warning_state.png index 99f1440..2e312fa 100644 Binary files a/test/app/create/deposit/widgets/goldens/range_selector_warning_state.png and b/test/app/create/deposit/widgets/goldens/range_selector_warning_state.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_success.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_success.png index 6e2ad4e..8e6773b 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_success.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_success.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_success_close_other_snackbar.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_success_close_other_snackbar.png index 6e2ad4e..8e6773b 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_success_close_other_snackbar.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_success_close_other_snackbar.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_token0_state.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_token0_state.png index b890375..537996f 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_token0_state.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_token0_state.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_token1_state.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_token1_state.png index 0315402..57ad59d 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_token1_state.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approve_token1_state.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approving_token.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approving_token.png index 9f6256b..c160efb 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approving_token.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_approving_token.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_approval_success_snackbar.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_approval_success_snackbar.png index 4142c45..a58cda7 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_approval_success_snackbar.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_approval_success_snackbar.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_approving_snackbar.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_approving_snackbar.png index 9a85546..252dc3f 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_approving_snackbar.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_approving_snackbar.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_deposit_success_modal.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_deposit_success_modal.png index 319ad5e..3101bea 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_deposit_success_modal.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_deposit_success_modal.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_depositing_snackbar.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_depositing_snackbar.png index 5ec8810..9c20337 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_depositing_snackbar.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_cubit_close_depositing_snackbar.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_current_price.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_current_price.png index 6241bf3..5ded858 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_current_price.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_current_price.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_current_price_reversed.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_current_price_reversed.png index 2915afa..1e7c3e3 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_current_price_reversed.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_current_price_reversed.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_current_price_stream.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_current_price_stream.png index 6241bf3..5ded858 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_current_price_stream.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_current_price_stream.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_deposit_state.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_deposit_state.png index 76cac48..aa05b38 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_deposit_state.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_deposit_state.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_deposit_success_modal.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_deposit_success_modal.png index 319ad5e..3101bea 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_deposit_success_modal.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_deposit_success_modal.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_depositing.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_depositing.png index 0a8c0ff..f6326be 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_depositing.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_depositing.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_in_range.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_in_range.png index c883e86..1f1a014 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_in_range.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_in_range.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_in_range_min_and_max_price.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_in_range_min_and_max_price.png index 5fa934a..2a91d0c 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_in_range_min_and_max_price.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_in_range_min_and_max_price.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_loading.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_loading.png index 989442e..791382a 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_loading.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_loading.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_max_price_infinity.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_max_price_infinity.png index 8a7a84c..923e5e3 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_max_price_infinity.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_max_price_infinity.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_min_price_infinity.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_min_price_infinity.png index 4c933fb..2cef97e 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_min_price_infinity.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_min_price_infinity.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_out_of_range_max_price.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_out_of_range_max_price.png index 623db87..571f572 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_out_of_range_max_price.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_out_of_range_max_price.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_out_of_range_min_price.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_out_of_range_min_price.png index 42b084e..cc52eea 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_out_of_range_min_price.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_out_of_range_min_price.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices.png index 7932452..0af78b4 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices_reversed.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices_reversed.png index 6f68b8f..7249e92 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices_reversed.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices_reversed.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices_reversed_manually.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices_reversed_manually.png index 79c2bce..7d34be4 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices_reversed_manually.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices_reversed_manually.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices_reversed_manually_reversed.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices_reversed_manually_reversed.png index 687e84b..3f7adf1 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices_reversed_manually_reversed.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_range_prices_reversed_manually_reversed.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_reversed.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_reversed.png index 6f68b8f..7249e92 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_reversed.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_reversed.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_reversed_manually.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_reversed_manually.png index 2915afa..1e7c3e3 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_reversed_manually.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_reversed_manually.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_show_desktop.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_show_desktop.png index f884b90..aaf1e60 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_show_desktop.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_show_desktop.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_show_mobile.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_show_mobile.png index 90534ed..1938481 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_show_mobile.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_show_mobile.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_slippage_check_error.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_slippage_check_error.png index 7d14d05..e3106b9 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_slippage_check_error.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_slippage_check_error.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_slippage_check_error_auto_slippage.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_slippage_check_error_auto_slippage.png index 1fffa64..8319116 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_slippage_check_error_auto_slippage.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_slippage_check_error_auto_slippage.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_token_amounts_change.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_token_amounts_change.png index 71ab6c7..389ceb2 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_token_amounts_change.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_token_amounts_change.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_transaction_error.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_transaction_error.png index 6c80556..f9b6a5f 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_transaction_error.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_transaction_error.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_unreversed_manually.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_unreversed_manually.png index 6241bf3..5ded858 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_unreversed_manually.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_unreversed_manually.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_waiting_transaction.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_waiting_transaction.png index 97a6398..f12ab67 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_waiting_transaction.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_waiting_transaction.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_waiting_transaction_button.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_waiting_transaction_button.png index 466d8d0..0aef7e9 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_waiting_transaction_button.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_waiting_transaction_button.png differ diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit_test.dart b/test/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit_test.dart index e875f66..f3f4e53 100644 --- a/test/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit_test.dart +++ b/test/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit_test.dart @@ -15,15 +15,15 @@ import 'package:zup_app/abis/uniswap_v3_pool.abi.g.dart'; import 'package:zup_app/abis/uniswap_v3_position_manager.abi.g.dart'; import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit.dart'; import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_constants.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/enums/pool_type.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/core/pool_service.dart'; import 'package:zup_app/core/slippage.dart'; import 'package:zup_app/core/zup_analytics.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; +import 'package:zup_ui_kit/zup_network_image.dart'; import '../../../../../golden_config.dart'; import '../../../../../mocks.dart'; @@ -31,7 +31,7 @@ import '../../../../../wrappers.dart'; void main() { final BigInt initialPoolSqrtPriceX96 = BigInt.from(21765); - final YieldDto currentYield = YieldDto.fixture(); + final LiquidityPoolDto currentYield = LiquidityPoolDto.fixture(); const transactionHash = "0x21"; late PreviewDepositModalCubit sut; @@ -81,7 +81,7 @@ void main() { registerFallbackValue(Slippage.halfPercent); registerFallbackValue(BigInt.one); registerFallbackValue((amount: BigInt.from(1), token: "")); - registerFallbackValue(YieldDto.fixture()); + registerFallbackValue(LiquidityPoolDto.fixture()); registerFallbackValue(Duration.zero); registerFallbackValue(( amount0Desired: BigInt.zero, @@ -233,7 +233,7 @@ void main() { Erc20? customErc20, Wallet? customWallet, UniswapV3PositionManager? customUniswapPositionManager, - YieldDto? customYield, + LiquidityPoolDto? customYield, GlobalKey? customNavigatorKey, UniswapPermit2? customPermit2, PoolService? customPoolService, @@ -315,10 +315,10 @@ void main() { """When calling `setup` it should get the yield tokens allowance from the connected signer and then emit the initial state with the allowance values""", () async { - final customYield = YieldDto.fixture().copyWith( + final customYield = LiquidityPoolDto.fixture().copyWith( chainId: AppNetworks.sepolia.chainId, - token0: TokenDto.fixture().copyWith(addresses: {AppNetworks.sepolia.chainId: "Token 0 Address"}), - token1: TokenDto.fixture().copyWith(addresses: {AppNetworks.sepolia.chainId: "Token 1 Address"}), + token0: SingleChainTokenDto.fixture().copyWith(address: "Token 0 Address"), + token1: SingleChainTokenDto.fixture().copyWith(address: "Token 1 Address"), ); sut = PreviewDepositModalCubit( @@ -340,14 +340,14 @@ void main() { when( () => erc20.fromRpcProvider( - contractAddress: customYield.token0.addresses[customYield.network.chainId]!, + contractAddress: customYield.token0.address, rpcUrl: any(named: "rpcUrl"), ), ).thenReturn(token0Contract); when( () => erc20.fromRpcProvider( - contractAddress: customYield.token1.addresses[customYield.network.chainId]!, + contractAddress: customYield.token1.address, rpcUrl: any(named: "rpcUrl"), ), ).thenReturn(token1Contract); @@ -379,7 +379,7 @@ void main() { ); test("When calling `approveToken` it should emit the approving token state with the token symbol", () async { - final token = TokenDto.fixture().copyWith(symbol: "TOKE SYMB"); + final token = SingleChainTokenDto.fixture().copyWith(symbol: "TOKE SYMB"); expectLater(sut.stream, emits(PreviewDepositModalState.approvingToken(token.symbol))); await sut.approveToken(token, BigInt.one); @@ -391,7 +391,7 @@ void main() { ask to switch the network""", () async { const yieldNetwork = AppNetworks.sepolia; - final customYield = YieldDto.fixture().copyWith(chainId: yieldNetwork.chainId); + final customYield = LiquidityPoolDto.fixture().copyWith(chainId: yieldNetwork.chainId); sut = PreviewDepositModalCubit( navigatorKey: GlobalKey(), @@ -423,7 +423,7 @@ void main() { ask to switch the network""", () async { const yieldNetwork = AppNetworks.sepolia; - final customYield = YieldDto.fixture().copyWith(chainId: yieldNetwork.chainId); + final customYield = LiquidityPoolDto.fixture().copyWith(chainId: yieldNetwork.chainId); sut = PreviewDepositModalCubit( navigatorKey: GlobalKey(), @@ -471,7 +471,7 @@ void main() { await sut.approveToken(token, tokenAmount); - verify(() => erc20.fromSigner(contractAddress: token.addresses[currentYield.chainId]!, signer: signer)).called(1); + verify(() => erc20.fromSigner(contractAddress: token.address, signer: signer)).called(1); verify(() => erc20Impl.approve(spender: currentYield.positionManagerAddress, value: tokenAmount)).called(1); }, ); @@ -543,7 +543,7 @@ void main() { when( () => erc20.fromRpcProvider( - contractAddress: currentYield.token0.addresses[currentYield.chainId]!, + contractAddress: currentYield.token0.address, rpcUrl: any(named: "rpcUrl"), ), ).thenReturn(token0Erc20Impl); @@ -576,7 +576,7 @@ void main() { when( () => erc20.fromRpcProvider( - contractAddress: currentYield.token1.addresses[currentYield.chainId]!, + contractAddress: currentYield.token1.address, rpcUrl: any(named: "rpcUrl"), ), ).thenReturn(token1Erc20Impl); @@ -610,7 +610,7 @@ void main() { when( () => erc20.fromRpcProvider( - contractAddress: currentYield.token0.addresses[currentYield.chainId]!, + contractAddress: currentYield.token0.address, rpcUrl: any(named: "rpcUrl"), ), ).thenReturn(token0Erc20Impl); @@ -654,7 +654,7 @@ void main() { when( () => erc20.fromRpcProvider( - contractAddress: currentYield.token1.addresses[currentYield.chainId]!, + contractAddress: currentYield.token1.address, rpcUrl: any(named: "rpcUrl"), ), ).thenReturn(token1Erc20Impl); @@ -1066,8 +1066,8 @@ void main() { tickLower: CLPoolConversorsMixinWrapper().tickToClosestValidTick( tick: CLPoolConversorsMixinWrapper().priceToTick( price: minPrice, - poolToken0Decimals: currentYield.token0NetworkDecimals, - poolToken1Decimals: currentYield.token1NetworkDecimals, + poolToken0Decimals: currentYield.token0.decimals, + poolToken1Decimals: currentYield.token1.decimals, isReversed: false, ), tickSpacing: currentYield.tickSpacing, @@ -1113,8 +1113,8 @@ void main() { tickLower: CLPoolConversorsMixinWrapper().tickToClosestValidTick( tick: CLPoolConversorsMixinWrapper().priceToTick( price: maxPrice, - poolToken0Decimals: currentYield.token0NetworkDecimals, - poolToken1Decimals: currentYield.token1NetworkDecimals, + poolToken0Decimals: currentYield.token0.decimals, + poolToken1Decimals: currentYield.token1.decimals, isReversed: isReversed, ), tickSpacing: currentYield.tickSpacing, @@ -1235,8 +1235,8 @@ void main() { tickUpper: CLPoolConversorsMixinWrapper().tickToClosestValidTick( tick: CLPoolConversorsMixinWrapper().priceToTick( price: maxPrice, - poolToken0Decimals: currentYield.token0NetworkDecimals, - poolToken1Decimals: currentYield.token1NetworkDecimals, + poolToken0Decimals: currentYield.token0.decimals, + poolToken1Decimals: currentYield.token1.decimals, isReversed: false, ), tickSpacing: currentYield.tickSpacing, @@ -1281,8 +1281,8 @@ void main() { tickUpper: CLPoolConversorsMixinWrapper().tickToClosestValidTick( tick: CLPoolConversorsMixinWrapper().priceToTick( price: minPrice, - poolToken0Decimals: currentYield.token0NetworkDecimals, - poolToken1Decimals: currentYield.token1NetworkDecimals, + poolToken0Decimals: currentYield.token0.decimals, + poolToken1Decimals: currentYield.token1.decimals, isReversed: isReversed, ), tickSpacing: currentYield.tickSpacing, @@ -1526,7 +1526,7 @@ void main() { setUp(() { final confettiController = ConfettiControllerMock(); - inject.registerFactory(() => mockZupCachedImage()); + inject.registerFactory(() => mockZupNetworkImage()); inject.registerFactory( () => confettiController, instanceName: InjectInstanceNames.confettiController10s, @@ -1609,7 +1609,7 @@ void main() { return TransactionReceipt(hash: ""); }); - await sut.approveToken(TokenDto.fixture(), BigInt.one); + await sut.approveToken(SingleChainTokenDto.fixture(), BigInt.one); // if waitConfirmation its not called, the test will fail. As the real test is // inside the stub of the waitConfirmation, it should change the `tested` variable @@ -1639,7 +1639,7 @@ void main() { return TransactionReceipt(hash: ""); }); - await sut.approveToken(TokenDto.fixture(), BigInt.one); + await sut.approveToken(SingleChainTokenDto.fixture(), BigInt.one); await tester.pumpAndSettle(); expect(sut.isClosed, true); @@ -1752,8 +1752,8 @@ void main() { verify( () => zupAnalytics.logDeposit( depositedYield: currentYield, - amount0Formatted: token0amount.parseTokenAmount(decimals: currentYield.token0NetworkDecimals), - amount1Formatted: token1amount.parseTokenAmount(decimals: currentYield.token1NetworkDecimals), + amount0Formatted: token0amount.parseTokenAmount(decimals: currentYield.token0.decimals), + amount1Formatted: token1amount.parseTokenAmount(decimals: currentYield.token1.decimals), walletAddress: userAddress, ), ).called(1); @@ -1823,7 +1823,7 @@ void main() { verify( () => permit2Impl.approve( - token: token.addresses[currentYield.network.chainId]!, + token: token.address, spender: currentYield0.positionManagerAddress, amount: EthereumConstants.uint160Max, expiration: EthereumConstants.uint48Max, @@ -1872,7 +1872,7 @@ void main() { verifyNever( () => permit2Impl.approve( - token: token.addresses[currentYield.network.chainId]!, + token: token.address, spender: currentYield0.positionManagerAddress, amount: EthereumConstants.uint160Max, expiration: EthereumConstants.uint48Max, @@ -1926,7 +1926,7 @@ void main() { verify( () => permit2Impl.approve( - token: token.addresses[currentYield.network.chainId]!, + token: token.address, spender: currentYield0.positionManagerAddress, amount: EthereumConstants.uint160Max, expiration: EthereumConstants.uint48Max, @@ -1982,8 +1982,8 @@ void main() { final tickLower = CLPoolConversorsMixinWrapper().tickToClosestValidTick( tick: CLPoolConversorsMixinWrapper().priceToTick( price: minPrice, - poolToken0Decimals: currentYield0.token0NetworkDecimals, - poolToken1Decimals: currentYield0.token1NetworkDecimals, + poolToken0Decimals: currentYield0.token0.decimals, + poolToken1Decimals: currentYield0.token1.decimals, ), tickSpacing: currentYield0.tickSpacing, ); @@ -1991,8 +1991,8 @@ void main() { final tickUpper = CLPoolConversorsMixinWrapper().tickToClosestValidTick( tick: CLPoolConversorsMixinWrapper().priceToTick( price: maxPrice, - poolToken0Decimals: currentYield0.token0NetworkDecimals, - poolToken1Decimals: currentYield0.token1NetworkDecimals, + poolToken0Decimals: currentYield0.token0.decimals, + poolToken1Decimals: currentYield0.token1.decimals, ), tickSpacing: currentYield0.tickSpacing, ); diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_test.dart b/test/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_test.dart index 99c9874..39fa1ec 100644 --- a/test/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_test.dart +++ b/test/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_test.dart @@ -15,17 +15,17 @@ import 'package:zup_app/abis/uniswap_v3_position_manager.abi.g.dart'; import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/widgets/preview_deposit_modal/preview_deposit_modal.dart'; import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit.dart'; import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_constants.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/core/pool_service.dart'; import 'package:zup_app/core/slippage.dart'; import 'package:zup_app/core/zup_analytics.dart'; import 'package:zup_app/core/zup_links.dart'; import 'package:zup_app/core/zup_navigator.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; import 'package:zup_ui_kit/zup_ui_kit.dart'; import '../../../../../golden_config.dart'; @@ -40,7 +40,7 @@ void main() { late PoolService poolService; late UniswapPermit2 permit2; final scaffoldMessengerKey = GlobalKey(); - final currentYield = YieldDto.fixture(); + final currentYield = LiquidityPoolDto.fixture(); setUp(() { navigator = ZupNavigatorMock(); @@ -52,7 +52,8 @@ void main() { UrlLauncherPlatform.instance = urlLauncherPlatform; - registerFallbackValue(TokenDto.fixture()); + registerFallbackValue(MultiChainTokenDto.fixture()); + registerFallbackValue(SingleChainTokenDto.fixture()); registerFallbackValue(BigInt.zero); registerFallbackValue(Duration.zero); registerFallbackValue(Slippage.fromValue(32)); @@ -68,7 +69,7 @@ void main() { inject.registerFactory(() => UniswapV3PositionManagerMock()); inject.registerFactory(() => WalletMock()); inject.registerLazySingleton(() => cubit); - inject.registerFactory(() => mockZupCachedImage()); + inject.registerFactory(() => mockZupNetworkImage()); inject.registerFactory(() => navigator); inject.registerFactory>(() => scaffoldMessengerKey); inject.registerFactory( @@ -113,7 +114,7 @@ void main() { }); Future goldenBuilder({ - YieldDto? customYield, + LiquidityPoolDto? customYield, bool isReversed = false, ({bool isInfinity, double price}) minPrice = (isInfinity: false, price: 1200), ({bool isInfinity, double price}) maxPrice = (isInfinity: false, price: 3000), @@ -133,7 +134,7 @@ void main() { content: BlocProvider.value( value: cubit, child: PreviewDepositModal( - yieldTimeFrame: YieldTimeFrame.day, + yieldTimeFrame: PoolDataTimeframe.day, deadline: deadline, maxSlippage: slippage, currentYield: customYield ?? currentYield, @@ -217,7 +218,7 @@ void main() { ); await tester.pumpDeviceBuilder( - await goldenBuilder(customYield: YieldDto.fixture().copyWith(chainId: yieldNetwork.chainId)), + await goldenBuilder(customYield: LiquidityPoolDto.fixture().copyWith(chainId: yieldNetwork.chainId)), wrapper: GoldenConfig.localizationsWrapper(), ); await tester.pumpAndSettle(); @@ -303,8 +304,8 @@ void main() { final currentPriceAsTick = CLPoolConversorsMixinWrapper().priceToTick( price: currentPrice, - poolToken0Decimals: currentYield.token0NetworkDecimals, - poolToken1Decimals: currentYield.token1NetworkDecimals, + poolToken0Decimals: currentYield.token0.decimals, + poolToken1Decimals: currentYield.token1.decimals, ); when(() => cubit.latestPriceX96).thenReturn(currentPriceAsTick); @@ -328,8 +329,8 @@ void main() { final currentPriceAsSqrtPrice = CLPoolLiquidityCalculationsMixinWrapper().getSqrtPriceAtTick( CLPoolConversorsMixinWrapper().priceToTick( price: currentPrice, - poolToken0Decimals: currentYield.token0NetworkDecimals, - poolToken1Decimals: currentYield.token1NetworkDecimals, + poolToken0Decimals: currentYield.token0.decimals, + poolToken1Decimals: currentYield.token1.decimals, ), ); @@ -357,8 +358,8 @@ void main() { final currentPriceAsSqrtPriceX96 = CLPoolLiquidityCalculationsMixinWrapper().getSqrtPriceAtTick( CLPoolConversorsMixinWrapper().priceToTick( price: currentPrice, - poolToken0Decimals: currentYield.token0NetworkDecimals, - poolToken1Decimals: currentYield.token1NetworkDecimals, + poolToken0Decimals: currentYield.token0.decimals, + poolToken1Decimals: currentYield.token1.decimals, ), ); @@ -536,7 +537,7 @@ void main() { verify( () => cubit.approveToken( currentYield.token0, - depositAmount.parseTokenAmount(decimals: currentYield.token0NetworkDecimals), + depositAmount.parseTokenAmount(decimals: currentYield.token0.decimals), ), ).called(1); }, @@ -553,7 +554,7 @@ void main() { when(() => cubit.state).thenReturn( PreviewDepositModalState.initial( - token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0NetworkDecimals), + token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0.decimals), token1Allowance: token1Allowance, ), ); @@ -561,7 +562,7 @@ void main() { when(() => cubit.stream).thenAnswer((_) { return Stream.value( PreviewDepositModalState.initial( - token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0NetworkDecimals), + token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0.decimals), token1Allowance: token1Allowance, ), ); @@ -593,7 +594,7 @@ void main() { when(() => cubit.state).thenReturn( PreviewDepositModalState.initial( - token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0NetworkDecimals), + token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0.decimals), token1Allowance: token1Allowance, ), ); @@ -601,7 +602,7 @@ void main() { when(() => cubit.stream).thenAnswer((_) { return Stream.value( PreviewDepositModalState.initial( - token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0NetworkDecimals), + token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0.decimals), token1Allowance: token1Allowance, ), ); @@ -622,7 +623,7 @@ void main() { verify( () => cubit.approveToken( currentYield.token1, - depositAmount.parseTokenAmount(decimals: currentYield.token1NetworkDecimals), + depositAmount.parseTokenAmount(decimals: currentYield.token1.decimals), ), ).called(1); }, @@ -634,8 +635,8 @@ void main() { in the deposit state""", goldenFileName: "preview_deposit_modal_deposit_state", (tester) async { - final token0Allowance = 400.parseTokenAmount(decimals: currentYield.token0NetworkDecimals); - final token1Allowance = 1200.parseTokenAmount(decimals: currentYield.token1NetworkDecimals); + final token0Allowance = 400.parseTokenAmount(decimals: currentYield.token0.decimals); + final token1Allowance = 1200.parseTokenAmount(decimals: currentYield.token1.decimals); const deposit0Amount = 100.2; const deposit1Amount = 110.2; @@ -667,8 +668,8 @@ void main() { in the deposit state. Once the deposit button is clicked, it should call the deposit function in the cubit passing the correct params (got from the constructor)""", (tester) async { - final token0Allowance = 400.parseTokenAmount(decimals: currentYield.token0NetworkDecimals); - final token1Allowance = 1200.parseTokenAmount(decimals: currentYield.token1NetworkDecimals); + final token0Allowance = 400.parseTokenAmount(decimals: currentYield.token0.decimals); + final token1Allowance = 1200.parseTokenAmount(decimals: currentYield.token1.decimals); const deposit0Amount = 100.2; const deposit1Amount = 110.2; @@ -716,8 +717,8 @@ void main() { maxPrice: maxPrice, minPrice: minPrice, slippage: slippage, - token0Amount: deposit0Amount.parseTokenAmount(decimals: currentYield.token0NetworkDecimals), - token1Amount: deposit1Amount.parseTokenAmount(decimals: currentYield.token1NetworkDecimals), + token0Amount: deposit0Amount.parseTokenAmount(decimals: currentYield.token0.decimals), + token1Amount: deposit1Amount.parseTokenAmount(decimals: currentYield.token1.decimals), ), ).called(1); }, @@ -730,8 +731,8 @@ void main() { when(() => cubit.latestPriceX96).thenReturn( CLPoolConversorsMixinWrapper().priceToTick( price: 0.01, // It should be shown in the card (or very close to it) - poolToken0Decimals: currentYield.token0NetworkDecimals, - poolToken1Decimals: currentYield.token1NetworkDecimals, + poolToken0Decimals: currentYield.token0.decimals, + poolToken1Decimals: currentYield.token1.decimals, isReversed: false, ), ); @@ -748,8 +749,8 @@ void main() { when(() => cubit.latestPriceX96).thenReturn( CLPoolConversorsMixinWrapper().priceToTick( price: 1200, // It should be shown in the card (or very close to it) - poolToken0Decimals: currentYield.token0NetworkDecimals, - poolToken1Decimals: currentYield.token1NetworkDecimals, + poolToken0Decimals: currentYield.token0.decimals, + poolToken1Decimals: currentYield.token1.decimals, isReversed: true, ), ); @@ -768,8 +769,8 @@ void main() { const newPrice = 0.02632; // It should be shown in the card (or very close to it) final newPriceAsTick = CLPoolConversorsMixinWrapper().priceToTick( price: newPrice, - poolToken0Decimals: currentYield.token0NetworkDecimals, - poolToken1Decimals: currentYield.token1NetworkDecimals, + poolToken0Decimals: currentYield.token0.decimals, + poolToken1Decimals: currentYield.token1.decimals, isReversed: false, ); @@ -910,7 +911,7 @@ void main() { builder: (context) { WidgetsBinding.instance.addPostFrameCallback((_) async { PreviewDepositModal( - yieldTimeFrame: YieldTimeFrame.day, + yieldTimeFrame: PoolDataTimeframe.day, currentYield: currentYield, isReversed: true, minPrice: (isInfinity: true, price: 0), @@ -945,7 +946,7 @@ void main() { builder: (context) { WidgetsBinding.instance.addPostFrameCallback((_) async { PreviewDepositModal( - yieldTimeFrame: YieldTimeFrame.day, + yieldTimeFrame: PoolDataTimeframe.day, currentYield: currentYield, isReversed: true, minPrice: (isInfinity: true, price: 0), diff --git a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_connected.png b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_connected.png index 22e202e..3c21e7e 100644 Binary files a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_connected.png and b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_connected.png differ diff --git a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_disabled.png b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_disabled.png index 241b1f2..e284ab3 100644 Binary files a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_disabled.png and b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_disabled.png differ diff --git a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_large_number_left_border.png b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_large_number_left_border.png index 08b30f9..d7dc0a2 100644 Binary files a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_large_number_left_border.png and b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_large_number_left_border.png differ diff --git a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_large_number_right_border.png b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_large_number_right_border.png index 43b418e..88c9e71 100644 Binary files a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_large_number_right_border.png and b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_large_number_right_border.png differ diff --git a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_non_number.png b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_non_number.png index 0f13290..457ab17 100644 Binary files a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_non_number.png and b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_non_number.png differ diff --git a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_not_connected.png b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_not_connected.png index cf7e17c..98d083c 100644 Binary files a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_not_connected.png and b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_not_connected.png differ diff --git a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_refresh.png b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_refresh.png index 7da8032..84f3a3b 100644 Binary files a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_refresh.png and b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_refresh.png differ diff --git a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_signer_changes.png b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_signer_changes.png index 22e202e..3c21e7e 100644 Binary files a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_signer_changes.png and b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_signer_changes.png differ diff --git a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_signer_changes_not_null.png b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_signer_changes_not_null.png index 22e202e..3c21e7e 100644 Binary files a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_signer_changes_not_null.png and b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_signer_changes_not_null.png differ diff --git a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_update_token.png b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_update_token.png index 7981c5f..8593fe3 100644 Binary files a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_update_token.png and b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_update_token.png differ diff --git a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_usd_equivalent.png b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_usd_equivalent.png index 8d99c51..fad572f 100644 Binary files a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_usd_equivalent.png and b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_usd_equivalent.png differ diff --git a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_user_balance_click.png b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_user_balance_click.png index 3f107ff..fe9f463 100644 Binary files a/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_user_balance_click.png and b/test/app/create/deposit/widgets/token_amount_input_card/goldens/token_amount_card_user_balance_click.png differ diff --git a/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_cubit_test.dart b/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_cubit_test.dart index 94b614e..43722c2 100644 --- a/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_cubit_test.dart +++ b/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_cubit_test.dart @@ -1,7 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/widgets/token_amount_input_card/token_amount_input_card_cubit.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; import 'package:zup_app/core/dtos/token_price_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/mixins/keys_mixin.dart'; @@ -36,14 +36,14 @@ void main() { when(() => zupHolder.hold(any())).thenAnswer((_) async => 31); final sut0 = TokenAmountInputCardCubit(tokensRepository, zupSingletonCache, zupHolder); - await sut0.getTokenPrice(token: TokenDto.fixture(), network: AppNetworks.sepolia); + await sut0.getTokenPrice(token: SingleChainTokenDto.fixture(), network: AppNetworks.sepolia); verify(() => zupHolder.hold(any())).called(1); }); test("When calling `getTokenPrice` it should use ZupSingletonCache with a expiration of 1 minute", () async { zupSingletonCache = ZupSingletonCacheMock(); final sut0 = TokenAmountInputCardCubit(tokensRepository, zupSingletonCache, zupHolder); - final token = TokenDto.fixture(); + final token = SingleChainTokenDto.fixture(); const network = AppNetworks.sepolia; when( @@ -59,16 +59,16 @@ void main() { () => zupSingletonCache.run( any(), expiration: const Duration(minutes: 1), - key: _KeysMixinWrapper().tokenPriceCacheKey(tokenAddress: token.addresses[network.chainId]!, network: network), + key: _KeysMixinWrapper().tokenPriceCacheKey(tokenAddress: token.address, network: network), ), ).called(1); }); test("When calling `getTokenPrice` it should use tokensRepository to get the token price", () async { - final token = TokenDto.fixture(); + final token = SingleChainTokenDto.fixture(); const network = AppNetworks.sepolia; await sut.getTokenPrice(token: token, network: network); - verify(() => tokensRepository.getTokenPrice(token.addresses[network.chainId]!, network)).called(1); + verify(() => tokensRepository.getTokenPrice(token.address, network)).called(1); }); } diff --git a/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_test.dart b/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_test.dart index de44162..d175043 100644 --- a/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_test.dart +++ b/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_test.dart @@ -6,13 +6,13 @@ import 'package:golden_toolkit/golden_toolkit.dart'; import 'package:mocktail/mocktail.dart'; import 'package:web3kit/web3kit.dart'; import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/widgets/token_amount_input_card/token_amount_input_card.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; import 'package:zup_app/core/dtos/token_price_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/core/repositories/tokens_repository.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; import 'package:zup_core/zup_core.dart'; +import 'package:zup_ui_kit/zup_network_image.dart'; import '../../../../../golden_config.dart'; import '../../../../../mocks.dart'; @@ -31,7 +31,7 @@ void main() { inject.registerFactory(() => wallet); inject.registerFactory(() => ZupSingletonCache.shared); - inject.registerFactory(() => mockZupCachedImage()); + inject.registerFactory(() => mockZupNetworkImage()); inject.registerFactory(() => tokensRepository); inject.registerFactory(() => ZupHolder()); @@ -55,7 +55,7 @@ void main() { TextEditingController? controller, AppNetworks network = AppNetworks.sepolia, Function(double)? onInput, - TokenDto? token, + SingleChainTokenDto? token, String? disabledText, bool isNative = false, }) async => await goldenDeviceBuilder( @@ -71,7 +71,7 @@ void main() { controller: controller ?? TextEditingController(), network: network, onInput: (value) => onInput?.call(value), - token: token ?? TokenDto.fixture(), + token: token ?? SingleChainTokenDto.fixture(), disabledText: disabledText, ), ), @@ -268,10 +268,7 @@ void main() { await tester.runAsync(() async { const key = Key("token-amount-card"); const newTokenAddress = "0xN3W_T0K3N"; - final newToken = TokenDto.fixture().copyWith( - addresses: {AppNetworks.sepolia.chainId: newTokenAddress}, - symbol: "NEW_TOKEN", - ); + final newToken = SingleChainTokenDto.fixture().copyWith(address: newTokenAddress, symbol: "NEW_TOKEN"); await tester.pumpDeviceBuilder(await goldenBuilder(key: key)); await tester.pumpDeviceBuilder(await goldenBuilder(key: key, token: newToken)); @@ -291,20 +288,13 @@ void main() { const key = Key("token-amount-card"); const oldNetwork = AppNetworks.sepolia; const newNetwork = AppNetworks.mainnet; - final token = TokenDto.fixture().copyWith( - addresses: { - oldNetwork.chainId: EthereumConstants.zeroAddress, - newNetwork.chainId: EthereumConstants.zeroAddress, - }, - ); + final token = SingleChainTokenDto.fixture().copyWith(address: EthereumConstants.zeroAddress); await tester.pumpDeviceBuilder(await goldenBuilder(key: key, network: oldNetwork, token: token)); await tester.pumpDeviceBuilder(await goldenBuilder(key: key, network: newNetwork, token: token)); await tester.pumpAndSettle(); - verify( - () => wallet.nativeOrTokenBalance(token.addresses[newNetwork.chainId]!, rpcUrl: newNetwork.rpcUrl), - ).called(1); + verify(() => wallet.nativeOrTokenBalance(token.address, rpcUrl: newNetwork.rpcUrl)).called(1); }); }, ); @@ -319,16 +309,10 @@ void main() { const newTokenNetwork = AppNetworks.sepolia; final oldTokenAddress = AppNetworks.scroll.wrappedNativeTokenAddress; - final oldToken = TokenDto.fixture().copyWith( - addresses: {AppNetworks.scroll.chainId: oldTokenAddress}, - symbol: "OLD_TOKEN", - ); + final oldToken = SingleChainTokenDto.fixture().copyWith(address: oldTokenAddress, symbol: "OLD_TOKEN"); final newTokenAddress = AppNetworks.sepolia.wrappedNativeTokenAddress; - final newToken = TokenDto.fixture().copyWith( - addresses: {AppNetworks.sepolia.chainId: newTokenAddress}, - symbol: "NEW_TOKEN", - ); + final newToken = SingleChainTokenDto.fixture().copyWith(address: newTokenAddress, symbol: "NEW_TOKEN"); await tester.pumpDeviceBuilder( await goldenBuilder(key: key, token: oldToken, isNative: true, network: oldTokenNetwork), @@ -356,16 +340,10 @@ void main() { const newTokenNetwork = AppNetworks.sepolia; final oldTokenAddress = AppNetworks.scroll.wrappedNativeTokenAddress; - final oldToken = TokenDto.fixture().copyWith( - addresses: {AppNetworks.scroll.chainId: oldTokenAddress}, - symbol: "OLD_TOKEN", - ); + final oldToken = SingleChainTokenDto.fixture().copyWith(address: oldTokenAddress, symbol: "OLD_TOKEN"); final newTokenAddress = AppNetworks.sepolia.wrappedNativeTokenAddress; - final newToken = TokenDto.fixture().copyWith( - addresses: {AppNetworks.sepolia.chainId: newTokenAddress}, - symbol: "NEW_TOKEN", - ); + final newToken = SingleChainTokenDto.fixture().copyWith(address: newTokenAddress, symbol: "NEW_TOKEN"); await tester.pumpDeviceBuilder( await goldenBuilder(key: key, token: oldToken, isNative: false, network: oldTokenNetwork), @@ -390,25 +368,26 @@ void main() { const oldTokenNetwork = AppNetworks.scroll; const newTokenNetwork = AppNetworks.sepolia; - final token = TokenDto.fixture().copyWith( - addresses: { - AppNetworks.scroll.chainId: AppNetworks.scroll.wrappedNativeTokenAddress, - AppNetworks.sepolia.chainId: AppNetworks.sepolia.wrappedNativeTokenAddress, - }, + final oldToken = SingleChainTokenDto.fixture().copyWith( + address: AppNetworks.scroll.wrappedNativeTokenAddress, + symbol: "OLD_TOKEN", ); + final newToken = SingleChainTokenDto.fixture().copyWith( + address: AppNetworks.sepolia.wrappedNativeTokenAddress, + symbol: "NEW_TOKO", + ); + await tester.pumpDeviceBuilder( - await goldenBuilder(key: key, token: token, isNative: false, network: oldTokenNetwork), + await goldenBuilder(key: key, token: oldToken, isNative: false, network: oldTokenNetwork), ); await tester.pumpDeviceBuilder( - await goldenBuilder(key: key, token: token, isNative: false, network: newTokenNetwork), + await goldenBuilder(key: key, token: newToken, isNative: false, network: newTokenNetwork), ); await tester.pumpAndSettle(); - verify( - () => wallet.nativeOrTokenBalance(token.addresses[newTokenNetwork.chainId]!, rpcUrl: newTokenNetwork.rpcUrl), - ).called(1); + verify(() => wallet.nativeOrTokenBalance(newToken.address, rpcUrl: newTokenNetwork.rpcUrl)).called(1); }); }, ); @@ -482,14 +461,14 @@ void main() { "When the wallet emits a new signer, and the current token is not native, it should fetch the non-native balance", (tester) async { await tester.runAsync(() async { - final token = TokenDto.fixture(); + final token = SingleChainTokenDto.fixture(); const network = AppNetworks.scroll; final signerStreamController = StreamController.broadcast(); when(() => wallet.signer).thenReturn(null); when(() => wallet.signerStream).thenAnswer((_) => signerStreamController.stream); - await tester.pumpDeviceBuilder(await goldenBuilder(isNative: false)); + await tester.pumpDeviceBuilder(await goldenBuilder(isNative: false, token: token, network: network)); await tester.pumpAndSettle(); when(() => wallet.signer).thenReturn(signer); @@ -497,9 +476,7 @@ void main() { signerStreamController.add(SignerMock()); await tester.pumpAndSettle(); - verify( - () => wallet.nativeOrTokenBalance(token.addresses[network.chainId]!, rpcUrl: any(named: "rpcUrl")), - ).called(1); + verify(() => wallet.nativeOrTokenBalance(token.address, rpcUrl: any(named: "rpcUrl"))).called(1); verifyNever(() => wallet.nativeOrTokenBalance(EthereumConstants.zeroAddress, rpcUrl: any(named: "rpcUrl"))); }); }, diff --git a/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_user_balance_cubit_test.dart b/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_user_balance_cubit_test.dart index 3a0bd7a..463be5b 100644 --- a/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_user_balance_cubit_test.dart +++ b/test/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_user_balance_cubit_test.dart @@ -5,7 +5,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:web3kit/web3kit.dart'; import 'package:zup_app/app/create/yields/%5Bid%5D/deposit/widgets/token_amount_input_card/token_amount_input_card_user_balance_cubit.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_core/zup_core.dart'; @@ -489,7 +489,7 @@ void main() { () {}, ); - final token = TokenDto.fixture(); + final token = MultiChainTokenDto.fixture(); const network = AppNetworks.sepolia; await sut0.updateTokenAndNetwork(token.addresses[network.chainId]!, network, asNativeToken: true); diff --git a/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_open.png b/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_open.png index 48a39a6..d73c1f0 100644 Binary files a/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_open.png and b/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_open.png differ diff --git a/test/app/create/goldens/create_page_select_tokens_stage_token_enabled_button.png b/test/app/create/goldens/create_page_select_tokens_stage_token_enabled_button.png index 8d49097..9459077 100644 Binary files a/test/app/create/goldens/create_page_select_tokens_stage_token_enabled_button.png and b/test/app/create/goldens/create_page_select_tokens_stage_token_enabled_button.png differ diff --git a/test/app/create/widgets/create_page_settings_dropdown_test.dart b/test/app/create/widgets/create_page_settings_dropdown_test.dart index 4518a9d..c48db2f 100644 --- a/test/app/create/widgets/create_page_settings_dropdown_test.dart +++ b/test/app/create/widgets/create_page_settings_dropdown_test.dart @@ -7,7 +7,7 @@ import 'package:zup_app/core/cache.dart'; import 'package:zup_app/core/debouncer.dart'; import 'package:zup_app/core/dtos/pool_search_settings_dto.dart'; import 'package:zup_app/core/injections.dart'; -import 'package:zup_core/zup_core.dart'; +import 'package:zup_core/test_utils.dart'; import '../../../golden_config.dart'; import '../../../mocks.dart'; @@ -29,11 +29,8 @@ void main() { tearDown(() => inject.reset()); - Future goldenBuilder() async => await goldenDeviceBuilder(Center( - child: CreatePageSettingsDropdown( - onClose: () {}, - ), - )); + Future goldenBuilder() async => + await goldenDeviceBuilder(Center(child: CreatePageSettingsDropdown(onClose: () {}))); zGoldenTest( "When initializing the widget, it should immediately assign the cached min pool tvl to the min tvl field", @@ -63,14 +60,17 @@ void main() { }, ); - zGoldenTest("When hovering over the info icon in the min tvl field, it should show a tooltip explaining the field", - goldenFileName: "create_page_settings_dropdown_min_liquidity_tooltip", (tester) async { - await tester.pumpDeviceBuilder(await goldenBuilder()); - await tester.pumpAndSettle(); + zGoldenTest( + "When hovering over the info icon in the min tvl field, it should show a tooltip explaining the field", + goldenFileName: "create_page_settings_dropdown_min_liquidity_tooltip", + (tester) async { + await tester.pumpDeviceBuilder(await goldenBuilder()); + await tester.pumpAndSettle(); - await tester.hover(find.byKey(const Key("min-liquidity-tooltip"))); - await tester.pumpAndSettle(); - }); + await tester.hover(find.byKey(const Key("min-liquidity-tooltip"))); + await tester.pumpAndSettle(); + }, + ); zGoldenTest( "When changing the min tvl field for a value less than the default, it should show a warning", @@ -88,24 +88,19 @@ void main() { }, ); - zGoldenTest( - "When typing in the min tvl field, it should update the cached min tvl", - (tester) async { - const typedMinLiquidity = 8721001234; - final poolSearchSettingsDto = cache.getPoolSearchSettings(); - await tester.pumpDeviceBuilder(await goldenBuilder()); - await tester.pumpAndSettle(); + zGoldenTest("When typing in the min tvl field, it should update the cached min tvl", (tester) async { + const typedMinLiquidity = 8721001234; + final poolSearchSettingsDto = cache.getPoolSearchSettings(); + await tester.pumpDeviceBuilder(await goldenBuilder()); + await tester.pumpAndSettle(); - await tester.enterText(find.byKey(const Key("min-liquidity-field")), typedMinLiquidity.toString()); - await tester.pumpAndSettle(); + await tester.enterText(find.byKey(const Key("min-liquidity-field")), typedMinLiquidity.toString()); + await tester.pumpAndSettle(); - verify( - () => cache.savePoolSearchSettings( - settings: poolSearchSettingsDto.copyWith(minLiquidityUSD: typedMinLiquidity), - ), - ).called(1); - }, - ); + verify( + () => cache.savePoolSearchSettings(settings: poolSearchSettingsDto.copyWith(minLiquidityUSD: typedMinLiquidity)), + ).called(1); + }); zGoldenTest( """When typing a non-numeric value in the min tvl field, it should not be written to the cache nor the field. @@ -120,164 +115,9 @@ void main() { verify( () => cache.savePoolSearchSettings( - settings: PoolSearchSettingsDto( - minLiquidityUSD: PoolSearchSettingsDto.defaultMinLiquidityUSD, - ), + settings: PoolSearchSettingsDto(minLiquidityUSD: PoolSearchSettingsDto.defaultMinLiquidityUSD), ), ).called(1); }, ); - - zGoldenTest( - "When hovering over the info icon in the allowed pool types section, it should show a tooltip explaining the field", - goldenFileName: "create_page_settings_dropdown_pool_types_tooltip_hover", - (tester) async { - await tester.pumpDeviceBuilder(await goldenBuilder()); - await tester.pumpAndSettle(); - - await tester.hover(find.byKey(const Key("pool-types-allowed-tooltip"))); - await tester.pumpAndSettle(); - }, - ); - - zGoldenTest("When clicking to disable the v4 switch, it should update the UI", - goldenFileName: "create_page_settings_dropdown_v4_pool_type_disabled", (tester) async { - when(() => cache.getPoolSearchSettings()).thenReturn( - PoolSearchSettingsDto().copyWith(allowV4Search: true), - ); - - await tester.pumpDeviceBuilder(await goldenBuilder()); - await tester.pumpAndSettle(); - - when(() => cache.getPoolSearchSettings()).thenReturn( - PoolSearchSettingsDto().copyWith(allowV4Search: false), - ); // using this when because it fetches again after click - - await tester.tap(find.byKey(const Key("pool-types-allowed-v4-switch"))); - await tester.pumpAndSettle(); - }); - - zGoldenTest("When clicking to disable the v3 switch, it should update the UI", - goldenFileName: "create_page_settings_dropdown_v3_pool_type_disabled", (tester) async { - when(() => cache.getPoolSearchSettings()).thenReturn( - PoolSearchSettingsDto().copyWith(allowV3Search: true), - ); - - await tester.pumpDeviceBuilder(await goldenBuilder()); - await tester.pumpAndSettle(); - - when(() => cache.getPoolSearchSettings()).thenReturn( - PoolSearchSettingsDto().copyWith(allowV3Search: false), - ); // using this when because it fetches again after click - - await tester.tap(find.byKey(const Key("pool-types-allowed-v3-switch"))); - await tester.pumpAndSettle(); - }); - - zGoldenTest( - "When clicking to disable the v4 switch, it should call the cache to update the settings only for the v4 switch", - (tester) async { - final initialSettings = PoolSearchSettingsDto.fixture().copyWith(allowV3Search: true, allowV4Search: true); - when(() => cache.getPoolSearchSettings()).thenReturn(initialSettings); - - await tester.pumpDeviceBuilder(await goldenBuilder()); - await tester.pumpAndSettle(); - - await tester.tap(find.byKey(const Key("pool-types-allowed-v4-switch"))); - await tester.pumpAndSettle(); - - verify( - () => cache.savePoolSearchSettings(settings: initialSettings.copyWith(allowV4Search: false)), - ).called(1); - }, - ); - - zGoldenTest( - "When clicking to disable the v3 switch, it should call the cache to update the settings only for the v3 switch", - (tester) async { - final initialSettings = PoolSearchSettingsDto.fixture().copyWith(allowV3Search: true, allowV4Search: true); - when(() => cache.getPoolSearchSettings()).thenReturn(initialSettings); - - await tester.pumpDeviceBuilder(await goldenBuilder()); - await tester.pumpAndSettle(); - - await tester.tap(find.byKey(const Key("pool-types-allowed-v3-switch"))); - await tester.pumpAndSettle(); - - verify( - () => cache.savePoolSearchSettings(settings: initialSettings.copyWith(allowV3Search: false)), - ).called(1); - }, - ); - - zGoldenTest("When clicking to enable the v4 switch, it should update the UI", - goldenFileName: "create_page_settings_dropdown_v4_pool_type_enable", (tester) async { - final initialSettings = PoolSearchSettingsDto.fixture().copyWith(allowV3Search: false, allowV4Search: false); - when(() => cache.getPoolSearchSettings()).thenReturn( - initialSettings, - ); - - await tester.pumpDeviceBuilder(await goldenBuilder()); - await tester.pumpAndSettle(); - - when(() => cache.getPoolSearchSettings()).thenReturn( - initialSettings.copyWith(allowV4Search: true), - ); // using this when because it fetches again after click - - await tester.tap(find.byKey(const Key("pool-types-allowed-v4-switch"))); - await tester.pumpAndSettle(); - }); - - zGoldenTest("When clicking to disable the v3 switch, it should update the UI", - goldenFileName: "create_page_settings_dropdown_v3_pool_type_enable", (tester) async { - final initialSettings = PoolSearchSettingsDto.fixture().copyWith(allowV3Search: false, allowV4Search: false); - - when(() => cache.getPoolSearchSettings()).thenReturn(initialSettings); - - await tester.pumpDeviceBuilder(await goldenBuilder()); - await tester.pumpAndSettle(); - - when(() => cache.getPoolSearchSettings()).thenReturn( - initialSettings.copyWith(allowV3Search: true), - ); // using this when because it fetches again after click - - await tester.tap(find.byKey(const Key("pool-types-allowed-v3-switch"))); - await tester.pumpAndSettle(); - }); - - zGoldenTest( - "When clicking to enable the v4 switch, it should call the cache to update the settings only for the v4 switch", - (tester) async { - final initialSettings = PoolSearchSettingsDto.fixture().copyWith(allowV3Search: false, allowV4Search: false); - when(() => cache.getPoolSearchSettings()).thenReturn(initialSettings); - - await tester.pumpDeviceBuilder(await goldenBuilder()); - await tester.pumpAndSettle(); - - await tester.tap(find.byKey(const Key("pool-types-allowed-v4-switch"))); - await tester.pumpAndSettle(); - - verify( - () => cache.savePoolSearchSettings(settings: initialSettings.copyWith(allowV4Search: true)), - ).called(1); - }, - ); - - zGoldenTest( - "When clicking to disable the v3 switch, it should call the cache to update the settings only for the v3 switch", - (tester) async { - final initialSettings = PoolSearchSettingsDto.fixture().copyWith(allowV3Search: false, allowV4Search: false); - when(() => cache.getPoolSearchSettings()).thenReturn(initialSettings); - - await tester.pumpDeviceBuilder(await goldenBuilder()); - await tester.pumpAndSettle(); - - await tester.tap(find.byKey(const Key("pool-types-allowed-v3-switch"))); - await tester.pumpAndSettle(); - - verify( - () => cache.savePoolSearchSettings(settings: initialSettings.copyWith(allowV3Search: true)), - ).called(1); - }, - ); } diff --git a/test/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button_test.dart b/test/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button_test.dart index b6d1fd4..2246757 100644 --- a/test/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button_test.dart +++ b/test/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button_test.dart @@ -7,8 +7,8 @@ import 'package:zup_app/core/cache.dart'; import 'package:zup_app/core/dtos/protocol_dto.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/core/repositories/protocol_repository.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; import 'package:zup_core/zup_singleton_cache.dart'; +import 'package:zup_ui_kit/zup_ui_kit.dart'; import '../../../../golden_config.dart'; import '../../../../mocks.dart'; @@ -16,13 +16,13 @@ import '../../../../mocks.dart'; void main() { late ZupSingletonCache zupSingletonCache; late ProtocolRepository protocolRepository; - late ZupCachedImage zupCachedImage; + late ZupNetworkImage zupCachedImage; late Cache cache; setUp(() { zupSingletonCache = ZupSingletonCache.shared; protocolRepository = ProtocolRepositoryMock(); - zupCachedImage = mockZupCachedImage(); + zupCachedImage = mockZupNetworkImage(); cache = CacheMock(); when(() => protocolRepository.getAllSupportedProtocols()).thenAnswer((_) => Future.value([])); @@ -30,7 +30,7 @@ void main() { inject.registerFactory(() => zupSingletonCache); inject.registerFactory(() => protocolRepository); - inject.registerFactory(() => zupCachedImage); + inject.registerFactory(() => zupCachedImage); inject.registerFactory(() => cache); }); diff --git a/test/app/create/widgets/exchanges_filter_dropdown_button/goldens/exchanges_filter_dropdown_button_error_click.png b/test/app/create/widgets/exchanges_filter_dropdown_button/goldens/exchanges_filter_dropdown_button_error_click.png index 165e054..f914f09 100644 Binary files a/test/app/create/widgets/exchanges_filter_dropdown_button/goldens/exchanges_filter_dropdown_button_error_click.png and b/test/app/create/widgets/exchanges_filter_dropdown_button/goldens/exchanges_filter_dropdown_button_error_click.png differ diff --git a/test/app/create/widgets/goldens/create_page_setting_dropdown_min_liquidity_non_numeric.png b/test/app/create/widgets/goldens/create_page_setting_dropdown_min_liquidity_non_numeric.png index c8f8253..bbe044c 100644 Binary files a/test/app/create/widgets/goldens/create_page_setting_dropdown_min_liquidity_non_numeric.png and b/test/app/create/widgets/goldens/create_page_setting_dropdown_min_liquidity_non_numeric.png differ diff --git a/test/app/create/widgets/goldens/create_page_settings_dropdown.png b/test/app/create/widgets/goldens/create_page_settings_dropdown.png index 02d2439..b4cef29 100644 Binary files a/test/app/create/widgets/goldens/create_page_settings_dropdown.png and b/test/app/create/widgets/goldens/create_page_settings_dropdown.png differ diff --git a/test/app/create/widgets/goldens/create_page_settings_dropdown_low_min_tvl_warning.png b/test/app/create/widgets/goldens/create_page_settings_dropdown_low_min_tvl_warning.png index 6ccfd89..55cbf99 100644 Binary files a/test/app/create/widgets/goldens/create_page_settings_dropdown_low_min_tvl_warning.png and b/test/app/create/widgets/goldens/create_page_settings_dropdown_low_min_tvl_warning.png differ diff --git a/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_tooltip.png b/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_tooltip.png index 56704c3..38d5a08 100644 Binary files a/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_tooltip.png and b/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_tooltip.png differ diff --git a/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_warning_field.png b/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_warning_field.png index 083d8ad..7bfab95 100644 Binary files a/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_warning_field.png and b/test/app/create/widgets/goldens/create_page_settings_dropdown_min_liquidity_warning_field.png differ diff --git a/test/app/create/yields/goldens/yields_page_open_pool_stats_modal.png b/test/app/create/yields/goldens/yields_page_open_pool_stats_modal.png new file mode 100644 index 0000000..5ff01cc Binary files /dev/null and b/test/app/create/yields/goldens/yields_page_open_pool_stats_modal.png differ diff --git a/test/app/create/yields/goldens/yields_page_open_pool_stats_modal_as_bottom_sheet.png b/test/app/create/yields/goldens/yields_page_open_pool_stats_modal_as_bottom_sheet.png new file mode 100644 index 0000000..9865aed Binary files /dev/null and b/test/app/create/yields/goldens/yields_page_open_pool_stats_modal_as_bottom_sheet.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_click_page_indicator.png b/test/app/create/yields/goldens/yields_page_success_click_page_indicator.png index 1c39b9e..269f9dc 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_click_page_indicator.png and b/test/app/create/yields/goldens/yields_page_success_click_page_indicator.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_first_page_coming_back.png b/test/app/create/yields/goldens/yields_page_success_first_page_coming_back.png index ab1f382..4fd0ded 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_first_page_coming_back.png and b/test/app/create/yields/goldens/yields_page_success_first_page_coming_back.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_first_page_left_button_disabled.png b/test/app/create/yields/goldens/yields_page_success_first_page_left_button_disabled.png index b3cf5bc..60dfe9e 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_first_page_left_button_disabled.png and b/test/app/create/yields/goldens/yields_page_success_first_page_left_button_disabled.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_hover_page_indicator.png b/test/app/create/yields/goldens/yields_page_success_hover_page_indicator.png index 4a7934a..1c1c2d5 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_hover_page_indicator.png and b/test/app/create/yields/goldens/yields_page_success_hover_page_indicator.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_min_tvl_warning.png b/test/app/create/yields/goldens/yields_page_success_min_tvl_warning.png index 5777679..e68d69e 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_min_tvl_warning.png and b/test/app/create/yields/goldens/yields_page_success_min_tvl_warning.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_mobile.png b/test/app/create/yields/goldens/yields_page_success_mobile.png index 559699c..6486fab 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_mobile.png and b/test/app/create/yields/goldens/yields_page_success_mobile.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_no_min_tvl_warning.png b/test/app/create/yields/goldens/yields_page_success_no_min_tvl_warning.png index daf6e75..450d444 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_no_min_tvl_warning.png and b/test/app/create/yields/goldens/yields_page_success_no_min_tvl_warning.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_odd_number_of_yields_last_page.png b/test/app/create/yields/goldens/yields_page_success_odd_number_of_yields_last_page.png index 19cd99a..cd17db3 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_odd_number_of_yields_last_page.png and b/test/app/create/yields/goldens/yields_page_success_odd_number_of_yields_last_page.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_one_yield_only.png b/test/app/create/yields/goldens/yields_page_success_one_yield_only.png index 5bb26d8..0b9cb82 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_one_yield_only.png and b/test/app/create/yields/goldens/yields_page_success_one_yield_only.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_second_page_left_button_enabled.png b/test/app/create/yields/goldens/yields_page_success_second_page_left_button_enabled.png index 26783e1..2a3e09b 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_second_page_left_button_enabled.png and b/test/app/create/yields/goldens/yields_page_success_second_page_left_button_enabled.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_sorted_by_30d.png b/test/app/create/yields/goldens/yields_page_success_sorted_by_30d.png index 359a54d..78032fe 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_sorted_by_30d.png and b/test/app/create/yields/goldens/yields_page_success_sorted_by_30d.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_sorted_by_7d.png b/test/app/create/yields/goldens/yields_page_success_sorted_by_7d.png index 4e499d6..a513aae 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_sorted_by_7d.png and b/test/app/create/yields/goldens/yields_page_success_sorted_by_7d.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_sorted_by_90d.png b/test/app/create/yields/goldens/yields_page_success_sorted_by_90d.png index 3b39070..0f62e74 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_sorted_by_90d.png and b/test/app/create/yields/goldens/yields_page_success_sorted_by_90d.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_sorted_reset_page.png b/test/app/create/yields/goldens/yields_page_success_sorted_reset_page.png index 4e499d6..a513aae 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_sorted_reset_page.png and b/test/app/create/yields/goldens/yields_page_success_sorted_reset_page.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_swipe_to_next_page.png b/test/app/create/yields/goldens/yields_page_success_swipe_to_next_page.png index 6b1a983..80e970c 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_swipe_to_next_page.png and b/test/app/create/yields/goldens/yields_page_success_swipe_to_next_page.png differ diff --git a/test/app/create/yields/goldens/yields_page_success_two_yields_only.png b/test/app/create/yields/goldens/yields_page_success_two_yields_only.png index 1de3aa1..5b165c3 100644 Binary files a/test/app/create/yields/goldens/yields_page_success_two_yields_only.png and b/test/app/create/yields/goldens/yields_page_success_two_yields_only.png differ diff --git a/test/app/create/yields/yields_cubit_test.dart b/test/app/create/yields/yields_cubit_test.dart index b1c510e..8721582 100644 --- a/test/app/create/yields/yields_cubit_test.dart +++ b/test/app/create/yields/yields_cubit_test.dart @@ -3,9 +3,9 @@ import 'package:mocktail/mocktail.dart'; import 'package:zup_app/app/app_cubit/app_cubit.dart'; import 'package:zup_app/app/create/yields/yields_cubit.dart'; import 'package:zup_app/core/cache.dart'; +import 'package:zup_app/core/dtos/liquidity_pools_search_result_dto.dart'; import 'package:zup_app/core/dtos/pool_search_filters_dto.dart'; import 'package:zup_app/core/dtos/pool_search_settings_dto.dart'; -import 'package:zup_app/core/dtos/yields_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/repositories/yield_repository.dart'; import 'package:zup_app/core/zup_analytics.dart'; @@ -98,11 +98,7 @@ void main() { all networks yields passing the correct ids and cached user preferences for the search""", () async { - final expectedPoolSearchSettings = PoolSearchSettingsDto( - allowV3Search: true, - allowV4Search: false, - minLiquidityUSD: 12618291, - ); + final expectedPoolSearchSettings = PoolSearchSettingsDto(minLiquidityUSD: 12618291); final expectedBlockedProtocolsIds = ["xasb12", "xasb13", "xasb14"]; const expectedToken0AddressOrId = "xabas1"; @@ -141,11 +137,7 @@ void main() { the selected network yields passing the correct ids and cached user preferences for the search""", () async { - final expectedPoolSearchSettings = PoolSearchSettingsDto( - allowV3Search: true, - allowV4Search: false, - minLiquidityUSD: 12618291, - ); + final expectedPoolSearchSettings = PoolSearchSettingsDto(minLiquidityUSD: 12618291); final expectedBlockedProtocolsIds = ["xasb12", "xasb13", "xasb14"]; const selectedNetwork = AppNetworks.mainnet; const expectedToken0AddressOrId = "xabas1"; @@ -184,11 +176,7 @@ void main() { it should ignore the cached min liquidity preference and pass 0 to the repository""", () async { - final savedPoolSearchSettings = PoolSearchSettingsDto( - allowV3Search: true, - allowV4Search: false, - minLiquidityUSD: 12618291, - ); + final savedPoolSearchSettings = PoolSearchSettingsDto(minLiquidityUSD: 12618291); when(() => appCache.getPoolSearchSettings()).thenReturn(savedPoolSearchSettings); when(() => appCubit.selectedNetwork).thenReturn(AppNetworks.allNetworks); @@ -221,11 +209,7 @@ void main() { it should ignore the cached min liquidity preference and pass 0 to the repository""", () async { - final savedPoolSearchSettings = PoolSearchSettingsDto( - allowV3Search: true, - allowV4Search: false, - minLiquidityUSD: 12618291, - ); + final savedPoolSearchSettings = PoolSearchSettingsDto(minLiquidityUSD: 12618291); when(() => appCache.getPoolSearchSettings()).thenReturn(savedPoolSearchSettings); when(() => appCubit.selectedNetwork).thenReturn(AppNetworks.mainnet); @@ -286,12 +270,7 @@ void main() { """When returning empty pools list for all networks search, it should emit empty state passing the returned filters applied""", () async { - const expectedFilters = PoolSearchFiltersDto( - allowedPoolTypes: ["xabasbab", "jajajajajajajajajaja"], - blockedProtocols: ["chaves", "kiko"], - minTvlUsd: 12618, - testnetMode: true, - ); + const expectedFilters = PoolSearchFiltersDto(blockedProtocols: ["chaves", "kiko"], minTvlUsd: 12618); when(() => appCubit.selectedNetwork).thenReturn(AppNetworks.allNetworks); @@ -304,7 +283,7 @@ void main() { searchSettings: any(named: "searchSettings"), blockedProtocolIds: any(named: "blockedProtocolIds"), ), - ).thenAnswer((_) async => const YieldsDto(pools: [], filters: expectedFilters)); + ).thenAnswer((_) async => const LiquidityPoolsSearchResultDto(pools: [], filters: expectedFilters)); await sut.fetchYields( token0AddressOrId: "token0AddressOrId", @@ -321,12 +300,7 @@ void main() { """When returning empty pools list for single network search, it should emit empty state passing the returned filters applied""", () async { - const expectedFilters = PoolSearchFiltersDto( - allowedPoolTypes: ["xabasbab", "jajajajajajajajajaja"], - blockedProtocols: ["chaves", "kiko"], - minTvlUsd: 12618, - testnetMode: true, - ); + const expectedFilters = PoolSearchFiltersDto(blockedProtocols: ["chaves", "kiko"], minTvlUsd: 12618); when(() => appCubit.selectedNetwork).thenReturn(AppNetworks.mainnet); @@ -340,7 +314,7 @@ void main() { searchSettings: any(named: "searchSettings"), blockedProtocolIds: any(named: "blockedProtocolIds"), ), - ).thenAnswer((_) async => const YieldsDto(pools: [], filters: expectedFilters)); + ).thenAnswer((_) async => const LiquidityPoolsSearchResultDto(pools: [], filters: expectedFilters)); await sut.fetchYields( token0AddressOrId: "token0AddressOrId", @@ -358,7 +332,7 @@ void main() { yield search, it should emit the success state,passing the whole DTO to the state""", () async { - final expectedYields = YieldsDto.fixture(); + final expectedYields = LiquidityPoolsSearchResultDto.fixture(); when(() => appCubit.selectedNetwork).thenReturn(AppNetworks.allNetworks); @@ -390,7 +364,7 @@ void main() { yield search, it should emit the success state, passing the whole DTO to the state""", () async { - final expectedYields = YieldsDto.fixture(); + final expectedYields = LiquidityPoolsSearchResultDto.fixture(); when(() => appCubit.selectedNetwork).thenReturn(AppNetworks.mainnet); diff --git a/test/app/create/yields/yields_page_test.dart b/test/app/create/yields/yields_page_test.dart index 44bab7a..9f29794 100644 --- a/test/app/create/yields/yields_page_test.dart +++ b/test/app/create/yields/yields_page_test.dart @@ -9,20 +9,21 @@ import 'package:zup_app/app/app_cubit/app_cubit.dart'; import 'package:zup_app/app/create/yields/yields_cubit.dart'; import 'package:zup_app/app/create/yields/yields_page.dart'; import 'package:zup_app/core/cache.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pools_search_result_dto.dart'; import 'package:zup_app/core/dtos/pool_search_filters_dto.dart'; import 'package:zup_app/core/dtos/pool_search_settings_dto.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; -import 'package:zup_app/core/dtos/yields_dto.dart'; +import 'package:zup_app/core/dtos/pool_stats_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/core/zup_navigator.dart'; import 'package:zup_app/core/zup_route_params_names.dart'; import 'package:zup_app/gen/assets.gen.dart'; import 'package:zup_app/widgets/yield_card.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; -import 'package:zup_core/extensions/extensions.dart'; +import 'package:zup_core/test_utils.dart'; +import 'package:zup_ui_kit/zup_ui_kit.dart'; import '../../../golden_config.dart'; import '../../../mocks.dart'; @@ -34,8 +35,8 @@ void main() { late Cache appCache; setUp(() { - registerFallbackValue(YieldDto.fixture()); - registerFallbackValue(YieldTimeFrame.day); + registerFallbackValue(LiquidityPoolDto.fixture()); + registerFallbackValue(PoolDataTimeframe.day); navigator = ZupNavigatorMock(); cubit = YieldsCubitMock(); @@ -76,7 +77,7 @@ void main() { instanceName: InjectInstanceNames.appScrollController, ); - inject.registerFactory(() => mockZupCachedImage()); + inject.registerFactory(() => mockZupNetworkImage()); inject.registerFactory(() => false, instanceName: InjectInstanceNames.infinityAnimationAutoPlay); @@ -285,8 +286,14 @@ void main() { (tester) async { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith( - pools: [YieldDto.fixture(), YieldDto.fixture(), YieldDto.fixture(), YieldDto.fixture(), YieldDto.fixture()], + LiquidityPoolsSearchResultDto.fixture().copyWith( + pools: [ + LiquidityPoolDto.fixture(), + LiquidityPoolDto.fixture(), + LiquidityPoolDto.fixture(), + LiquidityPoolDto.fixture(), + LiquidityPoolDto.fixture(), + ], ), ), ); @@ -302,13 +309,23 @@ void main() { (tester) async { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith( + LiquidityPoolsSearchResultDto.fixture().copyWith( pools: [ - YieldDto.fixture().copyWith(yield24h: 100), - YieldDto.fixture().copyWith(yield24h: 200), - YieldDto.fixture().copyWith(yield24h: 300), - YieldDto.fixture().copyWith(yield24h: 400), - YieldDto.fixture().copyWith(yield24h: 500), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 200), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 300), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 400), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 500), + ), ], ), ), @@ -329,13 +346,23 @@ void main() { (tester) async { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith( + LiquidityPoolsSearchResultDto.fixture().copyWith( pools: [ - YieldDto.fixture().copyWith(yield24h: 100), - YieldDto.fixture().copyWith(yield24h: 200), - YieldDto.fixture().copyWith(yield24h: 300), - YieldDto.fixture().copyWith(yield24h: 400), - YieldDto.fixture().copyWith(yield24h: 500), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 200), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 300), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 400), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 500), + ), ], ), ), @@ -359,13 +386,23 @@ void main() { (tester) async { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith( + LiquidityPoolsSearchResultDto.fixture().copyWith( pools: [ - YieldDto.fixture().copyWith(yield24h: 100), - YieldDto.fixture().copyWith(yield24h: 200), - YieldDto.fixture().copyWith(yield24h: 300), - YieldDto.fixture().copyWith(yield24h: 400), - YieldDto.fixture().copyWith(yield24h: 500), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 200), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 300), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 400), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 500), + ), ], ), ), @@ -382,8 +419,14 @@ void main() { (tester) async { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith( - pools: [YieldDto.fixture(), YieldDto.fixture(), YieldDto.fixture(), YieldDto.fixture(), YieldDto.fixture()], + LiquidityPoolsSearchResultDto.fixture().copyWith( + pools: [ + LiquidityPoolDto.fixture(), + LiquidityPoolDto.fixture(), + LiquidityPoolDto.fixture(), + LiquidityPoolDto.fixture(), + LiquidityPoolDto.fixture(), + ], ), ), ); @@ -405,13 +448,28 @@ void main() { (tester) async { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith( + LiquidityPoolsSearchResultDto.fixture().copyWith( pools: [ - YieldDto.fixture().copyWith(yield7d: 1000, yield24h: 1), - YieldDto.fixture().copyWith(yield7d: 2000, yield24h: 10), - YieldDto.fixture().copyWith(yield7d: 3000, yield24h: 100), - YieldDto.fixture().copyWith(yield7d: 4000, yield24h: 1000), - YieldDto.fixture().copyWith(yield7d: 5000, yield24h: 1000), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 2000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 10), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 3000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 4000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1000), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 5000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1000), + ), ], ), ), @@ -420,7 +478,7 @@ void main() { await tester.pumpDeviceBuilder(await goldenBuilder()); await tester.pumpAndSettle(); - await tester.tap(find.byKey(Key("${YieldTimeFrame.week.name}-timeframe-button"))); + await tester.tap(find.byKey(Key("${PoolDataTimeframe.week.name}-timeframe-button"))); await tester.pumpAndSettle(); }, ); @@ -432,13 +490,33 @@ void main() { (tester) async { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith( + LiquidityPoolsSearchResultDto.fixture().copyWith( pools: [ - YieldDto.fixture().copyWith(yield7d: 1000, yield24h: 1, yield30d: 2000), - YieldDto.fixture().copyWith(yield7d: 2000, yield24h: 10, yield30d: 4000), - YieldDto.fixture().copyWith(yield7d: 3000, yield24h: 100, yield30d: 6000), - YieldDto.fixture().copyWith(yield7d: 4000, yield24h: 1000, yield30d: 8000), - YieldDto.fixture().copyWith(yield7d: 5000, yield24h: 1000, yield30d: 10000), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 2000), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 2000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 10), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 4000), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 3000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 6000), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 4000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1000), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 8000), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 5000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1000), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 10000), + ), ], ), ), @@ -447,7 +525,7 @@ void main() { await tester.pumpDeviceBuilder(await goldenBuilder()); await tester.pumpAndSettle(); - await tester.tap(find.byKey(Key("${YieldTimeFrame.month.name}-timeframe-button"))); + await tester.tap(find.byKey(Key("${PoolDataTimeframe.month.name}-timeframe-button"))); await tester.pumpAndSettle(); }, ); @@ -459,13 +537,38 @@ void main() { (tester) async { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith( + LiquidityPoolsSearchResultDto.fixture().copyWith( pools: [ - YieldDto.fixture().copyWith(yield7d: 1000, yield24h: 1, yield30d: 2000, yield90d: 4000), - YieldDto.fixture().copyWith(yield7d: 2000, yield24h: 10, yield30d: 4000, yield90d: 8000), - YieldDto.fixture().copyWith(yield7d: 3000, yield24h: 100, yield30d: 6000, yield90d: 12000), - YieldDto.fixture().copyWith(yield7d: 4000, yield24h: 1000, yield30d: 8000, yield90d: 16000), - YieldDto.fixture().copyWith(yield7d: 5000, yield24h: 1000, yield30d: 10000, yield90d: 20000), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 2000), + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 4000), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 2000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 10), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 4000), + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 8000), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 3000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 6000), + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 12000), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 4000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1000), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 8000), + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 16000), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 5000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1000), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 10000), + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 20000), + ), ], ), ), @@ -474,7 +577,7 @@ void main() { await tester.pumpDeviceBuilder(await goldenBuilder()); await tester.pumpAndSettle(); - await tester.tap(find.byKey(Key("${YieldTimeFrame.threeMonth.name}-timeframe-button"))); + await tester.tap(find.byKey(Key("${PoolDataTimeframe.threeMonth.name}-timeframe-button"))); await tester.pumpAndSettle(); }, ); @@ -486,13 +589,38 @@ void main() { (tester) async { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith( + LiquidityPoolsSearchResultDto.fixture().copyWith( pools: [ - YieldDto.fixture().copyWith(yield7d: 1000, yield24h: 1, yield30d: 2000, yield90d: 4000), - YieldDto.fixture().copyWith(yield7d: 2000, yield24h: 10, yield30d: 4000, yield90d: 8000), - YieldDto.fixture().copyWith(yield7d: 3000, yield24h: 100, yield30d: 6000, yield90d: 12000), - YieldDto.fixture().copyWith(yield7d: 4000, yield24h: 1000, yield30d: 8000, yield90d: 16000), - YieldDto.fixture().copyWith(yield7d: 5000, yield24h: 1000, yield30d: 10000, yield90d: 20000), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 2000), + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 4000), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 2000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 10), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 4000), + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 8000), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 3000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 6000), + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 12000), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 4000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1000), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 8000), + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 16000), + ), + LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 5000), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1000), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 10000), + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 20000), + ), ], ), ), @@ -504,7 +632,7 @@ void main() { await tester.tap(find.byKey(const Key("move-to-next-yields-page-button"))); await tester.pumpAndSettle(); - await tester.tap(find.byKey(Key("${YieldTimeFrame.week.name}-timeframe-button"))); + await tester.tap(find.byKey(Key("${PoolDataTimeframe.week.name}-timeframe-button"))); await tester.pumpAndSettle(); }, ); @@ -516,13 +644,23 @@ void main() { (tester) async { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith( + LiquidityPoolsSearchResultDto.fixture().copyWith( pools: [ - YieldDto.fixture().copyWith(yield24h: 100), - YieldDto.fixture().copyWith(yield24h: 200), - YieldDto.fixture().copyWith(yield24h: 300), - YieldDto.fixture().copyWith(yield24h: 400), - YieldDto.fixture().copyWith(yield24h: 500), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 200), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 300), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 400), + ), + LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 500), + ), ], ), ), @@ -541,13 +679,15 @@ void main() { goldenFileName: "yields_page_success_odd_number_of_yields_last_page", (tester) async { final yields = [ - YieldDto.fixture().copyWith(yield24h: 100), - YieldDto.fixture().copyWith(yield24h: 200), - YieldDto.fixture().copyWith(yield24h: 300), - YieldDto.fixture().copyWith(yield24h: 400), - YieldDto.fixture().copyWith(yield24h: 400), + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100)), + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 200)), + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 300)), + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 400)), + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 500)), ]; - when(() => cubit.state).thenReturn(YieldsState.success(YieldsDto.fixture().copyWith(pools: yields))); + when( + () => cubit.state, + ).thenReturn(YieldsState.success(LiquidityPoolsSearchResultDto.fixture().copyWith(pools: yields))); await tester.pumpDeviceBuilder(await goldenBuilder()); await tester.pumpAndSettle(); @@ -564,8 +704,12 @@ void main() { the page controller and page indicator should not be visible""", goldenFileName: "yields_page_success_one_yield_only", (tester) async { - final yields = [YieldDto.fixture().copyWith(yield24h: 100)]; - when(() => cubit.state).thenReturn(YieldsState.success(YieldsDto.fixture().copyWith(pools: yields))); + final yields = [ + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100)), + ]; + when( + () => cubit.state, + ).thenReturn(YieldsState.success(LiquidityPoolsSearchResultDto.fixture().copyWith(pools: yields))); await tester.pumpDeviceBuilder(await goldenBuilder()); await tester.pumpAndSettle(); @@ -577,8 +721,13 @@ void main() { the page controller and page indicator should not be visible""", goldenFileName: "yields_page_success_two_yields_only", (tester) async { - final yields = [YieldDto.fixture().copyWith(yield24h: 100), YieldDto.fixture().copyWith(yield24h: 200)]; - when(() => cubit.state).thenReturn(YieldsState.success(YieldsDto.fixture().copyWith(pools: yields))); + final yields = [ + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100)), + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 200)), + ]; + when( + () => cubit.state, + ).thenReturn(YieldsState.success(LiquidityPoolsSearchResultDto.fixture().copyWith(pools: yields))); await tester.pumpDeviceBuilder(await goldenBuilder()); await tester.pumpAndSettle(); @@ -590,9 +739,15 @@ void main() { the page indicator size should be bigger""", goldenFileName: "yields_page_success_hover_page_indicator", (tester) async { - final yields = List.generate(10, (_) => YieldDto.fixture().copyWith(yield24h: 100)); + final yields = List.generate( + 10, + (_) => + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100)), + ); - when(() => cubit.state).thenReturn(YieldsState.success(YieldsDto.fixture().copyWith(pools: yields))); + when( + () => cubit.state, + ).thenReturn(YieldsState.success(LiquidityPoolsSearchResultDto.fixture().copyWith(pools: yields))); await tester.pumpDeviceBuilder(await goldenBuilder()); await tester.pumpAndSettle(); @@ -607,9 +762,16 @@ void main() { it should navigate to the corresponding page""", goldenFileName: "yields_page_success_click_page_indicator", (tester) async { - final yields = List.generate(10, (index) => YieldDto.fixture().copyWith(yield24h: 100 * index)); + final yields = List.generate( + 10, + (index) => LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100 * index), + ), + ); - when(() => cubit.state).thenReturn(YieldsState.success(YieldsDto.fixture().copyWith(pools: yields))); + when( + () => cubit.state, + ).thenReturn(YieldsState.success(LiquidityPoolsSearchResultDto.fixture().copyWith(pools: yields))); await tester.pumpDeviceBuilder(await goldenBuilder()); await tester.pumpAndSettle(); @@ -625,11 +787,19 @@ void main() { search was only done for pools with a min tvl of the specified USD""", goldenFileName: "yields_page_success_min_tvl_warning", (tester) async { - final yields = List.generate(2, (index) => YieldDto.fixture().copyWith(yield24h: 100 * index)); + final yields = List.generate( + 2, + (index) => LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100 * index), + ), + ); when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith(pools: yields, filters: const PoolSearchFiltersDto(minTvlUsd: 99898)), + LiquidityPoolsSearchResultDto.fixture().copyWith( + pools: yields, + filters: const PoolSearchFiltersDto(minTvlUsd: 99898), + ), ), ); @@ -643,7 +813,12 @@ void main() { it should refetch pools without the min usd filter (zero) but use the same params got from the url""", (tester) async { - final yields = List.generate(2, (index) => YieldDto.fixture().copyWith(yield24h: 100 * index)); + final yields = List.generate( + 2, + (index) => LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100 * index), + ), + ); const token0Id = "xabas"; const token1Id = "sabax"; const group0Id = "iuyip"; @@ -656,7 +831,10 @@ void main() { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith(pools: yields, filters: const PoolSearchFiltersDto(minTvlUsd: 99898)), + LiquidityPoolsSearchResultDto.fixture().copyWith( + pools: yields, + filters: const PoolSearchFiltersDto(minTvlUsd: 99898), + ), ), ); @@ -685,12 +863,20 @@ void main() { that the search was fone for all pools without a min tvl""", goldenFileName: "yields_page_success_no_min_tvl_warning", (tester) async { - final yields = List.generate(2, (index) => YieldDto.fixture().copyWith(yield24h: 100 * index)); + final yields = List.generate( + 2, + (index) => LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100 * index), + ), + ); when(() => appCache.getPoolSearchSettings()).thenReturn(PoolSearchSettingsDto(minLiquidityUSD: 122)); when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith(pools: yields, filters: const PoolSearchFiltersDto(minTvlUsd: 0)), + LiquidityPoolsSearchResultDto.fixture().copyWith( + pools: yields, + filters: const PoolSearchFiltersDto(minTvlUsd: 0), + ), ), ); @@ -704,7 +890,12 @@ void main() { without min tvl, it should refetch pools with the flag to ignore min usd false and use the same params got from the url at the initial request""", (tester) async { - final yields = List.generate(2, (index) => YieldDto.fixture().copyWith(yield24h: 100 * index)); + final yields = List.generate( + 2, + (index) => LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100 * index), + ), + ); const token0Id = "xabas"; const token1Id = "sabax"; const group0Id = "iuyip"; @@ -718,7 +909,10 @@ void main() { when(() => appCache.getPoolSearchSettings()).thenReturn(PoolSearchSettingsDto(minLiquidityUSD: 122)); when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith(pools: yields, filters: const PoolSearchFiltersDto(minTvlUsd: 0)), + LiquidityPoolsSearchResultDto.fixture().copyWith( + pools: yields, + filters: const PoolSearchFiltersDto(minTvlUsd: 0), + ), ), ); @@ -747,7 +941,10 @@ void main() { (tester) async { final yields = List.generate( 2, - (index) => YieldDto.fixture().copyWith(yield24h: 100 * index, poolAddress: "0x$index"), + (index) => LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100 * index), + poolAddress: "0x$index", + ), ); when( @@ -760,7 +957,10 @@ void main() { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith(pools: yields, filters: const PoolSearchFiltersDto(minTvlUsd: 0)), + LiquidityPoolsSearchResultDto.fixture().copyWith( + pools: yields, + filters: const PoolSearchFiltersDto(minTvlUsd: 0), + ), ), ); @@ -787,7 +987,10 @@ void main() { (tester) async { final yields = List.generate( 2, - (index) => YieldDto.fixture().copyWith(yield24h: 100 * index, poolAddress: "0x$index"), + (index) => LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100 * index), + poolAddress: "0x$index", + ), ); when( @@ -800,14 +1003,17 @@ void main() { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith(pools: yields, filters: const PoolSearchFiltersDto(minTvlUsd: 0)), + LiquidityPoolsSearchResultDto.fixture().copyWith( + pools: yields, + filters: const PoolSearchFiltersDto(minTvlUsd: 0), + ), ), ); await tester.pumpDeviceBuilder(await goldenBuilder()); await tester.pumpAndSettle(); - await tester.tap(find.byKey(Key("${YieldTimeFrame.week.name}-timeframe-button"))); + await tester.tap(find.byKey(Key("${PoolDataTimeframe.week.name}-timeframe-button"))); await tester.pumpAndSettle(); await tester.tap(find.byKey(Key("deposit-button-${yields[0].poolAddress}"))); @@ -817,7 +1023,7 @@ void main() { () => navigator.navigateToDeposit( yieldPool: any(named: "yieldPool"), parseWrappedToNative: any(named: "parseWrappedToNative"), - selectedTimeframe: YieldTimeFrame.week, + selectedTimeframe: PoolDataTimeframe.week, ), ).called(1); }, @@ -830,7 +1036,10 @@ void main() { (tester) async { final yields = List.generate( 2, - (index) => YieldDto.fixture().copyWith(yield24h: 100 * index, poolAddress: "0x$index"), + (index) => LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100 * index), + poolAddress: "0x$index", + ), ); when( @@ -843,14 +1052,17 @@ void main() { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith(pools: yields, filters: const PoolSearchFiltersDto(minTvlUsd: 0)), + LiquidityPoolsSearchResultDto.fixture().copyWith( + pools: yields, + filters: const PoolSearchFiltersDto(minTvlUsd: 0), + ), ), ); await tester.pumpDeviceBuilder(await goldenBuilder()); await tester.pumpAndSettle(); - await tester.tap(find.byKey(Key("${YieldTimeFrame.month.name}-timeframe-button"))); + await tester.tap(find.byKey(Key("${PoolDataTimeframe.month.name}-timeframe-button"))); await tester.pumpAndSettle(); await tester.tap(find.byKey(Key("deposit-button-${yields[0].poolAddress}"))); @@ -860,7 +1072,7 @@ void main() { () => navigator.navigateToDeposit( yieldPool: any(named: "yieldPool"), parseWrappedToNative: any(named: "parseWrappedToNative"), - selectedTimeframe: YieldTimeFrame.month, + selectedTimeframe: PoolDataTimeframe.month, ), ).called(1); }, @@ -874,7 +1086,10 @@ void main() { (tester) async { final yields = List.generate( 2, - (index) => YieldDto.fixture().copyWith(yield24h: 100 * index, poolAddress: "0x$index"), + (index) => LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100 * index), + poolAddress: "0x$index", + ), ); when( @@ -887,14 +1102,17 @@ void main() { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith(pools: yields, filters: const PoolSearchFiltersDto(minTvlUsd: 0)), + LiquidityPoolsSearchResultDto.fixture().copyWith( + pools: yields, + filters: const PoolSearchFiltersDto(minTvlUsd: 0), + ), ), ); await tester.pumpDeviceBuilder(await goldenBuilder()); await tester.pumpAndSettle(); - await tester.tap(find.byKey(Key("${YieldTimeFrame.day.name}-timeframe-button"))); + await tester.tap(find.byKey(Key("${PoolDataTimeframe.day.name}-timeframe-button"))); await tester.pumpAndSettle(); await tester.tap(find.byKey(Key("deposit-button-${yields[0].poolAddress}"))); @@ -904,7 +1122,7 @@ void main() { () => navigator.navigateToDeposit( yieldPool: any(named: "yieldPool"), parseWrappedToNative: any(named: "parseWrappedToNative"), - selectedTimeframe: YieldTimeFrame.day, + selectedTimeframe: PoolDataTimeframe.day, ), ).called(1); }, @@ -920,11 +1138,11 @@ void main() { final yields = List.generate( 2, - (index) => YieldDto.fixture().copyWith( - yield24h: 100 * index, + (index) => LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100 * index), poolAddress: "0x$index", chainId: yieldNetwork.chainId, - token0: TokenDto(addresses: {yieldNetwork.chainId: EthereumConstants.zeroAddress}), + token0: const SingleChainTokenDto(address: EthereumConstants.zeroAddress), ), ); @@ -938,7 +1156,10 @@ void main() { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith(pools: yields, filters: const PoolSearchFiltersDto(minTvlUsd: 0)), + LiquidityPoolsSearchResultDto.fixture().copyWith( + pools: yields, + filters: const PoolSearchFiltersDto(minTvlUsd: 0), + ), ), ); @@ -968,11 +1189,11 @@ void main() { final yields = List.generate( 2, - (index) => YieldDto.fixture().copyWith( - yield24h: 100 * index, + (index) => LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100 * index), poolAddress: "0x$index", chainId: yieldNetwork.chainId, - token1: TokenDto(addresses: {yieldNetwork.chainId: EthereumConstants.zeroAddress}), + token1: const SingleChainTokenDto(address: EthereumConstants.zeroAddress), ), ); @@ -986,7 +1207,10 @@ void main() { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith(pools: yields, filters: const PoolSearchFiltersDto(minTvlUsd: 0)), + LiquidityPoolsSearchResultDto.fixture().copyWith( + pools: yields, + filters: const PoolSearchFiltersDto(minTvlUsd: 0), + ), ), ); @@ -1016,11 +1240,11 @@ void main() { final yields = List.generate( 2, - (index) => YieldDto.fixture().copyWith( - yield24h: 100 * index, + (index) => LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100 * index), poolAddress: "0x$index", chainId: yieldNetwork.chainId, - token1: TokenDto(addresses: {yieldNetwork.chainId: yieldNetwork.wrappedNativeTokenAddress}), + token1: SingleChainTokenDto(address: yieldNetwork.wrappedNativeTokenAddress), ), ); @@ -1034,7 +1258,10 @@ void main() { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith(pools: yields, filters: const PoolSearchFiltersDto(minTvlUsd: 0)), + LiquidityPoolsSearchResultDto.fixture().copyWith( + pools: yields, + filters: const PoolSearchFiltersDto(minTvlUsd: 0), + ), ), ); @@ -1064,11 +1291,11 @@ void main() { final yields = List.generate( 2, - (index) => YieldDto.fixture().copyWith( - yield24h: 100 * index, + (index) => LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100 * index), poolAddress: "0x$index", chainId: yieldNetwork.chainId, - token0: TokenDto(addresses: {yieldNetwork.chainId: yieldNetwork.wrappedNativeTokenAddress}), + token0: SingleChainTokenDto(address: yieldNetwork.wrappedNativeTokenAddress), ), ); @@ -1082,7 +1309,10 @@ void main() { when(() => cubit.state).thenReturn( YieldsState.success( - YieldsDto.fixture().copyWith(pools: yields, filters: const PoolSearchFiltersDto(minTvlUsd: 0)), + LiquidityPoolsSearchResultDto.fixture().copyWith( + pools: yields, + filters: const PoolSearchFiltersDto(minTvlUsd: 0), + ), ), ); @@ -1101,4 +1331,38 @@ void main() { ).called(1); }, ); + + zGoldenTest( + "When clicking the pool stats button in the yield card, it should open the pool info side panel", + goldenFileName: "yields_page_open_pool_stats_modal", + (tester) async { + final yields = [LiquidityPoolDto.fixture()]; + when( + () => cubit.state, + ).thenReturn(YieldsState.success(LiquidityPoolsSearchResultDto.fixture().copyWith(pools: yields))); + + await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(Key("pool-stats-button-${yields[0].poolAddress}"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When clicking the pool stats button in the yield card, and the device is mobile, it should open the pool info as bottom sheet", + goldenFileName: "yields_page_open_pool_stats_modal_as_bottom_sheet", + (tester) async { + final yields = [LiquidityPoolDto.fixture()]; + when( + () => cubit.state, + ).thenReturn(YieldsState.success(LiquidityPoolsSearchResultDto.fixture().copyWith(pools: yields))); + + await tester.pumpDeviceBuilder(await goldenBuilder(isMobile: true), wrapper: GoldenConfig.localizationsWrapper()); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(Key("pool-stats-button-${yields[0].poolAddress}"))); + await tester.pumpAndSettle(); + }, + ); } diff --git a/test/app/goldens/app_layout_cookie_consent_not_null.png b/test/app/goldens/app_layout_cookie_consent_not_null.png index a4f1d6e..a60004a 100644 Binary files a/test/app/goldens/app_layout_cookie_consent_not_null.png and b/test/app/goldens/app_layout_cookie_consent_not_null.png differ diff --git a/test/app/goldens/app_layout_cookie_consent_null.png b/test/app/goldens/app_layout_cookie_consent_null.png index e635da5..087bc91 100644 Binary files a/test/app/goldens/app_layout_cookie_consent_null.png and b/test/app/goldens/app_layout_cookie_consent_null.png differ diff --git a/test/app/goldens/app_layout_footer_desktop.png b/test/app/goldens/app_layout_footer_desktop.png index 8ca4896..931241b 100644 Binary files a/test/app/goldens/app_layout_footer_desktop.png and b/test/app/goldens/app_layout_footer_desktop.png differ diff --git a/test/app/goldens/app_layout_footer_mobile.png b/test/app/goldens/app_layout_footer_mobile.png index 7968402..2d76951 100644 Binary files a/test/app/goldens/app_layout_footer_mobile.png and b/test/app/goldens/app_layout_footer_mobile.png differ diff --git a/test/app/goldens/app_layout_navbar.png b/test/app/goldens/app_layout_navbar.png index fb6939e..bef0584 100644 Binary files a/test/app/goldens/app_layout_navbar.png and b/test/app/goldens/app_layout_navbar.png differ diff --git a/test/app/goldens/app_layout_top_app_bar.png b/test/app/goldens/app_layout_top_app_bar.png index a4f1d6e..a60004a 100644 Binary files a/test/app/goldens/app_layout_top_app_bar.png and b/test/app/goldens/app_layout_top_app_bar.png differ diff --git a/test/core/concentrated_liquidity_utils/cl_pool_constants_test.dart b/test/core/concentrated_liquidity_utils/cl_pool_constants_test.dart index e52f624..f9636d5 100644 --- a/test/core/concentrated_liquidity_utils/cl_pool_constants_test.dart +++ b/test/core/concentrated_liquidity_utils/cl_pool_constants_test.dart @@ -17,4 +17,8 @@ void main() { test("Q32 should be the correct value", () { expect(CLPoolConstants.q32, BigInt.from(2).pow(32)); }); + + test("feeTierFactor should be the correct value", () { + expect(CLPoolConstants.feeTierFactor, 10000); + }); } diff --git a/test/core/dtos/liquidity_pool_dto_test.dart b/test/core/dtos/liquidity_pool_dto_test.dart new file mode 100644 index 0000000..db47a2b --- /dev/null +++ b/test/core/dtos/liquidity_pool_dto_test.dart @@ -0,0 +1,554 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:web3kit/core/ethereum_constants.dart'; +import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_constants.dart'; +import 'package:zup_app/core/dtos/hook_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/dtos/pool_stats_dto.dart'; +import 'package:zup_app/core/dtos/protocol_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; +import 'package:zup_app/core/enums/networks.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; +import 'package:zup_app/core/extensions/num_extension.dart'; + +void main() { + test("When calling `isToken0Native` and the token0 address in the yield network is zero, it should return true", () { + const network = AppNetworks.sepolia; + expect( + LiquidityPoolDto.fixture() + .copyWith( + chainId: network.chainId, + token0: SingleChainTokenDto.fixture().copyWith(address: EthereumConstants.zeroAddress), + ) + .isToken0Native, + true, + ); + }); + + test("When calling `isToken1Native` and the token1 address in the yield network is zero, it should return true", () { + const network = AppNetworks.sepolia; + expect( + LiquidityPoolDto.fixture() + .copyWith( + chainId: network.chainId, + token1: SingleChainTokenDto.fixture().copyWith(address: EthereumConstants.zeroAddress), + ) + .isToken1Native, + true, + ); + }); + + test("When calling `isToken0Native` and the token0 address in the yield network is not, it should return false", () { + const network = AppNetworks.sepolia; + expect( + LiquidityPoolDto.fixture() + .copyWith( + chainId: network.chainId, + token0: SingleChainTokenDto.fixture().copyWith(address: "0x1"), + ) + .isToken0Native, + false, + ); + }); + + test("When calling `isToken1Native` and the token1 address in the yield network is not, it should return false", () { + const network = AppNetworks.sepolia; + expect( + LiquidityPoolDto.fixture() + .copyWith( + chainId: network.chainId, + token1: SingleChainTokenDto.fixture().copyWith(address: "0x1"), + ) + .isToken1Native, + false, + ); + }); + + test("When calling 'yieldTimeframed' passing a 24h timeframe, it should get the 24h yield", () { + const yield24h = 261782; + final currentYield = LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: yield24h), + ); + + expect(currentYield.yieldTimeframed(PoolDataTimeframe.day), yield24h); + }); + + test("When calling 'yieldTimeframed' passing a 7d timeframe, it should get the 90d yield", () { + const yield7d = 819028190; + final currentYield = LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: yield7d), + ); + + expect(currentYield.yieldTimeframed(PoolDataTimeframe.week), yield7d); + }); + + test("When calling 'yieldTimeframed' passing a 30d timeframe, it should get the 90d yield", () { + const yield30d = 8.9787678; + final currentYield = LiquidityPoolDto.fixture().copyWith( + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: yield30d), + ); + + expect(currentYield.yieldTimeframed(PoolDataTimeframe.month), yield30d); + }); + + test("When calling 'yieldTimeframed' passing a 90d timeframe, it should get the 90d yield", () { + const yield90d = 12718728.222; + final currentYield = LiquidityPoolDto.fixture().copyWith( + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: yield90d), + ); + + expect(currentYield.yieldTimeframed(PoolDataTimeframe.threeMonth), yield90d); + }); + + test("When building the yield dto with default variables, the deployerAddress should be zero address by default", () { + expect( + LiquidityPoolDto( + token0: SingleChainTokenDto.fixture(), + token1: SingleChainTokenDto.fixture(), + poolAddress: "0x1", + chainId: AppNetworks.sepolia.chainId, + positionManagerAddress: "0x2", + tickSpacing: 1, + protocol: ProtocolDto.fixture(), + initialFeeTier: 0, + currentFeeTier: 0, + ).deployerAddress, + EthereumConstants.zeroAddress, + ); + }); + + test("When building the yield dto with default variables, the hooks should be null", () { + expect( + LiquidityPoolDto( + token0: SingleChainTokenDto.fixture(), + token1: SingleChainTokenDto.fixture(), + poolAddress: "0x1", + chainId: AppNetworks.sepolia.chainId, + positionManagerAddress: "0x2", + tickSpacing: 1, + protocol: ProtocolDto.fixture(), + initialFeeTier: 0, + currentFeeTier: 0, + ).hook, + null, + ); + }); + + test( + """When using 'timeframedYieldFormatted' passing day timeframe, + and the 24h yield is not zero it should return me the formatted + 24h yield with percent sign""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 2.3213), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.day), "2.3%"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing week timeframe, + and the 7d yield is not zero it should return me the formatted + 7d yield with percent sign""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 121.335), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.week), "121.3%"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing month timeframe, + and the 30d yield is not zero it should return me the formatted + 30d yield with percent sign""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 11.335), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.month), "11.3%"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing a three month timeframe, + and the 90d yield is not zero it should return me the formatted + 90d yield with percent sign""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 99.87), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.threeMonth), "99.9%"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing day timeframe, + and the 24h yield is zero it should return me just a hyphen""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.day), "-"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing week timeframe, + and the 7d yield is zero it should return me just a hyphen""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.week), "-"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing month timeframe, + and the 30d yield is zero it should return me just a hyphen""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.month), "-"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing three months + timeframe, and the 90d yield is zero it should return me just a hyphen""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.threeMonth), "-"); + }, + ); + + test( + """When using 'currentFeeTierFormatted' it should return the current + fee tier divided by the fee tier factor (10000) as percentage""", + () { + const currentFeeTier = 10000; + final yieldDto = LiquidityPoolDto.fixture().copyWith(currentFeeTier: currentFeeTier); + + expect(yieldDto.currentFeeTierFormatted, "${currentFeeTier / CLPoolConstants.feeTierFactor}%"); + }, + ); + + test("When using 'isDynamicFee' and the hook is null, it should return false", () { + final yieldDto = LiquidityPoolDto.fixture().copyWith(hook: null); + + expect(yieldDto.isDynamicFee, false); + }); + + test("When using 'isDynamicFee' and the hook has the property is dynamic fee false, it should return false", () { + final yieldDto = LiquidityPoolDto.fixture().copyWith(hook: HookDto.fixture().copyWith(isDynamicFee: false)); + + expect(yieldDto.isDynamicFee, false); + }); + + test("When using 'isDynamicFee' and the hook has the property is dynamic fee true, it should return true", () { + final yieldDto = LiquidityPoolDto.fixture().copyWith(hook: HookDto.fixture().copyWith(isDynamicFee: true)); + + expect(yieldDto.isDynamicFee, true); + }); + + test( + """When using 'createdAtMillisecondsTimestamp' it should multiply the createdAtTimestamp + of the pool by 1000 to convert it from seconds to milliseconds""", + () { + const createdAtTimestamp = 1666000000; + final yieldDto = LiquidityPoolDto.fixture().copyWith(createdAtTimestamp: createdAtTimestamp); + + expect(yieldDto.createdAtMillisecondsTimestamp, createdAtTimestamp * 1000); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing the day timeframe, + but the total24hStats yield is zero,it should return just a hyphen""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.day), "-"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing the week timeframe, + but the total7dStats yield is zero, it should return just a hyphen""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.week), "-"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing the month timeframe, + but the total30dStats yield is zero, it should return just a hyphen""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.month), "-"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing the three months timeframe, + but the total90dStats yield is zero, it should return just a hyphen""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.threeMonth), "-"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing the day timeframe, + but the total24hStats is null, it should return just a hyphen""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith(total24hStats: null); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.day), "-"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing the week timeframe, + but the total7dStats is null, it should return just a hyphen""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith(total7dStats: null); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.week), "-"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing the month timeframe, + but the total30dStats is null, it should return just a hyphen""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith(total30dStats: null); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.month), "-"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing the three months timeframe, + but the total90dStats is null, it should return just a hyphen""", + () { + final yieldDto = LiquidityPoolDto.fixture().copyWith(total90dStats: null); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.threeMonth), "-"); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing the day timeframe, and it's not zero, + it should return the formatted yield as a percentage""", + () { + const yearlyYield = 999; + + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: yearlyYield), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.day), yearlyYield.formatRoundingPercent); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing the week timeframe, and it's not zero, + it should return the formatted yield as a percentage""", + () { + const yearlyYield = 1212.12; + + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: yearlyYield), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.week), yearlyYield.formatRoundingPercent); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing the month timeframe, and it's not zero, + it should return the formatted yield as a percentage""", + () { + const yearlyYield = 128.11; + + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: yearlyYield), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.month), yearlyYield.formatRoundingPercent); + }, + ); + + test( + """When using 'timeframedYieldFormatted' passing the three months timeframe, and it's not zero, + it should return the formatted yield as a percentage""", + () { + const yearlyYield = 2157821.212; + + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: yearlyYield), + ); + expect(yieldDto.timeframedYieldFormatted(PoolDataTimeframe.threeMonth), yearlyYield.formatRoundingPercent); + }, + ); + + group("volumeTimeframed", () { + test("When calling 'volumeTimeframed' passing a 24h timeframe, it should return the 24h total volume", () { + const volume24h = 1000.5; + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(totalVolume: volume24h), + ); + + expect(yieldDto.volumeTimeframed(PoolDataTimeframe.day), volume24h); + }); + + test("When calling 'volumeTimeframed' passing a 7d timeframe, it should return the 7d total volume", () { + const volume7d = 55000.12; + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(totalVolume: volume7d), + ); + + expect(yieldDto.volumeTimeframed(PoolDataTimeframe.week), volume7d); + }); + + test("When calling 'volumeTimeframed' passing a 30d timeframe, it should return the 30d total volume", () { + const volume30d = 812312.999; + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total30dStats: PoolTotalStatsDTO.fixture().copyWith(totalVolume: volume30d), + ); + + expect(yieldDto.volumeTimeframed(PoolDataTimeframe.month), volume30d); + }); + + test("When calling 'volumeTimeframed' passing a 90d timeframe, it should return the 90d total volume", () { + const volume90d = 987654.321; + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total90dStats: PoolTotalStatsDTO.fixture().copyWith(totalVolume: volume90d), + ); + + expect(yieldDto.volumeTimeframed(PoolDataTimeframe.threeMonth), volume90d); + }); + + test("When calling 'volumeTimeframed' but the timeframe stats are null, it should return 0", () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total24hStats: null, + total7dStats: null, + total30dStats: null, + total90dStats: null, + ); + + expect(yieldDto.volumeTimeframed(PoolDataTimeframe.day), 0); + expect(yieldDto.volumeTimeframed(PoolDataTimeframe.week), 0); + expect(yieldDto.volumeTimeframed(PoolDataTimeframe.month), 0); + expect(yieldDto.volumeTimeframed(PoolDataTimeframe.threeMonth), 0); + }); + }); + + group("feesTimeframed", () { + test("When calling 'feesTimeframed' passing a 24h timeframe, it should return the 24h total fees", () { + const fees24h = 123.45; + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(totalFees: fees24h), + ); + + expect(yieldDto.feesTimeframed(PoolDataTimeframe.day), fees24h); + }); + + test("When calling 'feesTimeframed' passing a 7d timeframe, it should return the 7d total fees", () { + const fees7d = 1000.99; + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(totalFees: fees7d), + ); + + expect(yieldDto.feesTimeframed(PoolDataTimeframe.week), fees7d); + }); + + test("When calling 'feesTimeframed' passing a 30d timeframe, it should return the 30d total fees", () { + const fees30d = 12345.67; + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total30dStats: PoolTotalStatsDTO.fixture().copyWith(totalFees: fees30d), + ); + + expect(yieldDto.feesTimeframed(PoolDataTimeframe.month), fees30d); + }); + + test("When calling 'feesTimeframed' passing a 90d timeframe, it should return the 90d total fees", () { + const fees90d = 999999.99; + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total90dStats: PoolTotalStatsDTO.fixture().copyWith(totalFees: fees90d), + ); + + expect(yieldDto.feesTimeframed(PoolDataTimeframe.threeMonth), fees90d); + }); + + test("When calling 'feesTimeframed' but the timeframe stats are null, it should return 0", () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total24hStats: null, + total7dStats: null, + total30dStats: null, + total90dStats: null, + ); + + expect(yieldDto.feesTimeframed(PoolDataTimeframe.day), 0); + expect(yieldDto.feesTimeframed(PoolDataTimeframe.week), 0); + expect(yieldDto.feesTimeframed(PoolDataTimeframe.month), 0); + expect(yieldDto.feesTimeframed(PoolDataTimeframe.threeMonth), 0); + }); + }); + group("netInflowTimeframed", () { + test("When calling 'netInflowTimeframed' passing a 24h timeframe, it should return the 24h total net inflow", () { + const netInflow24h = 500.25; + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(totalNetInflow: netInflow24h), + ); + + expect(yieldDto.netInflowTimeframed(PoolDataTimeframe.day), netInflow24h); + }); + + test("When calling 'netInflowTimeframed' passing a 7d timeframe, it should return the 7d total net inflow", () { + const netInflow7d = 12345.67; + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(totalNetInflow: netInflow7d), + ); + + expect(yieldDto.netInflowTimeframed(PoolDataTimeframe.week), netInflow7d); + }); + + test("When calling 'netInflowTimeframed' passing a 30d timeframe, it should return the 30d total net inflow", () { + const netInflow30d = 999999.99; + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total30dStats: PoolTotalStatsDTO.fixture().copyWith(totalNetInflow: netInflow30d), + ); + + expect(yieldDto.netInflowTimeframed(PoolDataTimeframe.month), netInflow30d); + }); + + test("When calling 'netInflowTimeframed' passing a 90d timeframe, it should return the 90d total net inflow", () { + const netInflow90d = 8888888.888; + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total90dStats: PoolTotalStatsDTO.fixture().copyWith(totalNetInflow: netInflow90d), + ); + + expect(yieldDto.netInflowTimeframed(PoolDataTimeframe.threeMonth), netInflow90d); + }); + + test("When calling 'netInflowTimeframed' but the timeframe stats are null, it should return 0", () { + final yieldDto = LiquidityPoolDto.fixture().copyWith( + total24hStats: null, + total7dStats: null, + total30dStats: null, + total90dStats: null, + ); + + expect(yieldDto.netInflowTimeframed(PoolDataTimeframe.day), 0); + expect(yieldDto.netInflowTimeframed(PoolDataTimeframe.week), 0); + expect(yieldDto.netInflowTimeframed(PoolDataTimeframe.month), 0); + expect(yieldDto.netInflowTimeframed(PoolDataTimeframe.threeMonth), 0); + }); + }); +} diff --git a/test/core/dtos/liquidity_pools_search_result_dto_test.dart b/test/core/dtos/liquidity_pools_search_result_dto_test.dart new file mode 100644 index 0000000..042952e --- /dev/null +++ b/test/core/dtos/liquidity_pools_search_result_dto_test.dart @@ -0,0 +1,129 @@ +import 'package:collection/collection.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pools_search_result_dto.dart'; +import 'package:zup_app/core/dtos/pool_stats_dto.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; + +void main() { + test("When calling 'poolsSortedBy24hYield' it should short pools descending by 24h yield", () { + final pools = [ + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100)), + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 87)), + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0)), + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 2000)), + ]; + + final yields = LiquidityPoolsSearchResultDto.fixture().copyWith(pools: pools); + + expect( + yields.poolsSortedBy24hYield, + pools.sorted((a, b) => b.total24hStats!.yearlyYield.compareTo(a.total24hStats!.yearlyYield)), + ); + }); + + test("When calling 'poolsSortedBy7dYield' it should short pools descending by 7d yield", () { + final pools = [ + LiquidityPoolDto.fixture().copyWith(total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 12681)), + LiquidityPoolDto.fixture().copyWith(total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 111)), + LiquidityPoolDto.fixture().copyWith(total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0)), + LiquidityPoolDto.fixture().copyWith(total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 21971972891)), + ]; + + final yields = LiquidityPoolsSearchResultDto.fixture().copyWith(pools: pools); + + expect( + yields.poolsSortedBy7dYield, + pools.sorted((a, b) => b.total7dStats!.yearlyYield.compareTo(a.total7dStats!.yearlyYield)), + ); + }); + + test("When calling 'poolsSortedBy30dYield' it should short pools descending by 30d yield", () { + final pools = [ + LiquidityPoolDto.fixture().copyWith(total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 089889888)), + LiquidityPoolDto.fixture().copyWith(total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 2222)), + LiquidityPoolDto.fixture().copyWith(total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0)), + LiquidityPoolDto.fixture().copyWith(total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 12615654)), + ]; + + final yields = LiquidityPoolsSearchResultDto.fixture().copyWith(pools: pools); + + expect( + yields.poolsSortedBy30dYield, + pools.sorted((a, b) => b.total30dStats!.yearlyYield.compareTo(a.total30dStats!.yearlyYield)), + ); + }); + + test("When calling 'poolsSortedBy90dYield' it should short pools descending by 90d yield", () { + final pools = [ + LiquidityPoolDto.fixture().copyWith(total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 978888)), + LiquidityPoolDto.fixture().copyWith(total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 121)), + LiquidityPoolDto.fixture().copyWith(total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0)), + LiquidityPoolDto.fixture().copyWith(total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 329087902)), + ]; + + final yields = LiquidityPoolsSearchResultDto.fixture().copyWith(pools: pools); + + expect( + yields.poolsSortedBy90dYield, + pools.sorted((a, b) => b.total90dStats!.yearlyYield.compareTo(a.total90dStats!.yearlyYield)), + ); + }); + + test("when calling 'poolsSortedByTimeframe' passing YieldTimeFrame.day it should return poolsSortedBy24hYield", () { + final pools = [ + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 100)), + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 87)), + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0)), + LiquidityPoolDto.fixture().copyWith(total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 2000)), + ]; + + final yields = LiquidityPoolsSearchResultDto.fixture().copyWith(pools: pools); + + expect(yields.poolsSortedByTimeframe(PoolDataTimeframe.day), yields.poolsSortedBy24hYield); + }); + + test("when calling 'poolsSortedByTimeframe' passing YieldTimeFrame.week it should return poolsSortedBy7dYield", () { + final pools = [ + LiquidityPoolDto.fixture().copyWith(total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 12681)), + LiquidityPoolDto.fixture().copyWith(total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 111)), + LiquidityPoolDto.fixture().copyWith(total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0)), + LiquidityPoolDto.fixture().copyWith(total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 21971972891)), + ]; + + final yields = LiquidityPoolsSearchResultDto.fixture().copyWith(pools: pools); + + expect(yields.poolsSortedByTimeframe(PoolDataTimeframe.week), yields.poolsSortedBy7dYield); + }); + + test("when calling 'poolsSortedByTimeframe' passing YieldTimeFrame.month it should return poolsSortedBy30dYield", () { + final pools = [ + LiquidityPoolDto.fixture().copyWith(total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 089889888)), + LiquidityPoolDto.fixture().copyWith(total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 2222)), + LiquidityPoolDto.fixture().copyWith(total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0)), + LiquidityPoolDto.fixture().copyWith(total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 12615654)), + ]; + + final yields = LiquidityPoolsSearchResultDto.fixture().copyWith(pools: pools); + + expect(yields.poolsSortedByTimeframe(PoolDataTimeframe.month), yields.poolsSortedBy30dYield); + }); + + test( + "when calling 'poolsSortedByTimeframe' passing YieldTimeFrame.threeMonth it should return poolsSortedBy90dYield", + () { + final pools = [ + LiquidityPoolDto.fixture().copyWith(total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 978888)), + LiquidityPoolDto.fixture().copyWith(total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 121)), + LiquidityPoolDto.fixture().copyWith(total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 0)), + LiquidityPoolDto.fixture().copyWith( + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 329087902), + ), + ]; + + final yields = LiquidityPoolsSearchResultDto.fixture().copyWith(pools: pools); + + expect(yields.poolsSortedByTimeframe(PoolDataTimeframe.threeMonth), yields.poolsSortedBy90dYield); + }, + ); +} diff --git a/test/core/dtos/yield_dto_test.dart b/test/core/dtos/yield_dto_test.dart deleted file mode 100644 index 63fe0d1..0000000 --- a/test/core/dtos/yield_dto_test.dart +++ /dev/null @@ -1,199 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:web3kit/core/ethereum_constants.dart'; -import 'package:zup_app/core/dtos/protocol_dto.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; -import 'package:zup_app/core/enums/networks.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; - -void main() { - test("When calling `isToken0Native` and the token0 address in the yield network is zero, it should return true", () { - const network = AppNetworks.sepolia; - expect( - YieldDto.fixture() - .copyWith( - chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: EthereumConstants.zeroAddress}), - ) - .isToken0Native, - true, - ); - }); - - test("When calling `isToken1Native` and the token1 address in the yield network is zero, it should return true", () { - const network = AppNetworks.sepolia; - expect( - YieldDto.fixture() - .copyWith( - chainId: network.chainId, - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: EthereumConstants.zeroAddress}), - ) - .isToken1Native, - true, - ); - }); - - test("When calling `isToken0Native` and the token0 address in the yield network is not, it should return false", () { - const network = AppNetworks.sepolia; - expect( - YieldDto.fixture() - .copyWith( - chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x1"}), - ) - .isToken0Native, - false, - ); - }); - - test("When calling `isToken1Native` and the token1 address in the yield network is not, it should return false", () { - const network = AppNetworks.sepolia; - expect( - YieldDto.fixture() - .copyWith( - chainId: network.chainId, - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x1"}), - ) - .isToken1Native, - false, - ); - }); - - test("When calling 'yieldTimeframed' passing a 24h timeframe, it should get the 24h yield", () { - const yield24h = 261782; - final currentYield = YieldDto.fixture().copyWith(yield24h: yield24h); - - expect(currentYield.yieldTimeframed(YieldTimeFrame.day), yield24h); - }); - - test("When calling 'yieldTimeframed' passing a 7d timeframe, it should get the 90d yield", () { - const yield7d = 819028190; - final currentYield = YieldDto.fixture().copyWith(yield7d: yield7d); - - expect(currentYield.yieldTimeframed(YieldTimeFrame.week), yield7d); - }); - - test("When calling 'yieldTimeframed' passing a 30d timeframe, it should get the 90d yield", () { - const yield30d = 8.9787678; - final currentYield = YieldDto.fixture().copyWith(yield30d: yield30d); - - expect(currentYield.yieldTimeframed(YieldTimeFrame.month), yield30d); - }); - - test("When calling 'yieldTimeframed' passing a 90d timeframe, it should get the 90d yield", () { - const yield90d = 12718728.222; - final currentYield = YieldDto.fixture().copyWith(yield90d: yield90d); - - expect(currentYield.yieldTimeframed(YieldTimeFrame.threeMonth), yield90d); - }); - - test("When building the yield dto with default variables, the deployerAddress should be zero address by default", () { - expect( - YieldDto( - token0: TokenDto.fixture(), - token1: TokenDto.fixture(), - poolAddress: "0x1", - chainId: AppNetworks.sepolia.chainId, - positionManagerAddress: "0x2", - tickSpacing: 1, - protocol: ProtocolDto.fixture(), - initialFeeTier: 0, - currentFeeTier: 0, - ).deployerAddress, - EthereumConstants.zeroAddress, - ); - }); - - test("When building the yield dto with default variables, the hooks should be zero address by default", () { - expect( - YieldDto( - token0: TokenDto.fixture(), - token1: TokenDto.fixture(), - poolAddress: "0x1", - chainId: AppNetworks.sepolia.chainId, - positionManagerAddress: "0x2", - tickSpacing: 1, - protocol: ProtocolDto.fixture(), - initialFeeTier: 0, - currentFeeTier: 0, - ).v4Hooks, - EthereumConstants.zeroAddress, - ); - }); - - test( - """When using 'timeframedYieldFormatted' passing day timeframe, - and the 24h yield is not zero it should return me the formatted - 24h yield with percent sign""", - () { - final yieldDto = YieldDto.fixture().copyWith(yield24h: 2.3213); - expect(yieldDto.timeframedYieldFormatted(YieldTimeFrame.day), "2.3%"); - }, - ); - - test( - """When using 'timeframedYieldFormatted' passing week timeframe, - and the 7d yield is not zero it should return me the formatted - 7d yield with percent sign""", - () { - final yieldDto = YieldDto.fixture().copyWith(yield7d: 121.335); - expect(yieldDto.timeframedYieldFormatted(YieldTimeFrame.week), "121.3%"); - }, - ); - - test( - """When using 'timeframedYieldFormatted' passing month timeframe, - and the 30d yield is not zero it should return me the formatted - 30d yield with percent sign""", - () { - final yieldDto = YieldDto.fixture().copyWith(yield30d: 11.335); - expect(yieldDto.timeframedYieldFormatted(YieldTimeFrame.month), "11.3%"); - }, - ); - - test( - """When using 'timeframedYieldFormatted' passing a three month timeframe, - and the 90d yield is not zero it should return me the formatted - 90d yield with percent sign""", - () { - final yieldDto = YieldDto.fixture().copyWith(yield90d: 99.87); - expect(yieldDto.timeframedYieldFormatted(YieldTimeFrame.threeMonth), "99.9%"); - }, - ); - - test( - """When using 'timeframedYieldFormatted' passing day timeframe, - and the 24h yield is zero it should return me just a hyphen""", - () { - final yieldDto = YieldDto.fixture().copyWith(yield24h: 0); - expect(yieldDto.timeframedYieldFormatted(YieldTimeFrame.day), "-"); - }, - ); - - test( - """When using 'timeframedYieldFormatted' passing week timeframe, - and the 7d yield is zero it should return me just a hyphen""", - () { - final yieldDto = YieldDto.fixture().copyWith(yield7d: 0); - expect(yieldDto.timeframedYieldFormatted(YieldTimeFrame.week), "-"); - }, - ); - - test( - """When using 'timeframedYieldFormatted' passing month timeframe, - and the 30d yield is zero it should return me just a hyphen""", - () { - final yieldDto = YieldDto.fixture().copyWith(yield30d: 0); - expect(yieldDto.timeframedYieldFormatted(YieldTimeFrame.month), "-"); - }, - ); - - test( - """When using 'timeframedYieldFormatted' passing three months - timeframe, and the 90d yield is zero it should return me just a hyphen""", - () { - final yieldDto = YieldDto.fixture().copyWith(yield90d: 0); - expect(yieldDto.timeframedYieldFormatted(YieldTimeFrame.threeMonth), "-"); - }, - ); -} diff --git a/test/core/dtos/yields_dto_test.dart b/test/core/dtos/yields_dto_test.dart deleted file mode 100644 index 152faf9..0000000 --- a/test/core/dtos/yields_dto_test.dart +++ /dev/null @@ -1,114 +0,0 @@ -import 'package:collection/collection.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; -import 'package:zup_app/core/dtos/yields_dto.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; - -void main() { - test("When calling 'poolsSortedBy24hYield' it should short pools descending by 24h yield", () { - final pools = [ - YieldDto.fixture().copyWith(yield24h: 100), - YieldDto.fixture().copyWith(yield24h: 87), - YieldDto.fixture().copyWith(yield24h: 0), - YieldDto.fixture().copyWith(yield24h: 2000), - ]; - - final yields = YieldsDto.fixture().copyWith(pools: pools); - - expect(yields.poolsSortedBy24hYield, pools.sorted((a, b) => b.yield24h.compareTo(a.yield24h))); - }); - - test("When calling 'poolsSortedBy7dYield' it should short pools descending by 7d yield", () { - final pools = [ - YieldDto.fixture().copyWith(yield7d: 12681), - YieldDto.fixture().copyWith(yield7d: 111), - YieldDto.fixture().copyWith(yield7d: 0), - YieldDto.fixture().copyWith(yield7d: 21971972891), - ]; - - final yields = YieldsDto.fixture().copyWith(pools: pools); - - expect(yields.poolsSortedBy7dYield, pools.sorted((a, b) => b.yield7d.compareTo(a.yield7d))); - }); - - test("When calling 'poolsSortedBy30dYield' it should short pools descending by 30d yield", () { - final pools = [ - YieldDto.fixture().copyWith(yield30d: 089889888), - YieldDto.fixture().copyWith(yield30d: 2222), - YieldDto.fixture().copyWith(yield30d: 0), - YieldDto.fixture().copyWith(yield30d: 12615654), - ]; - - final yields = YieldsDto.fixture().copyWith(pools: pools); - - expect(yields.poolsSortedBy30dYield, pools.sorted((a, b) => b.yield30d.compareTo(a.yield30d))); - }); - - test("When calling 'poolsSortedBy90dYield' it should short pools descending by 90d yield", () { - final pools = [ - YieldDto.fixture().copyWith(yield90d: 978888), - YieldDto.fixture().copyWith(yield90d: 121), - YieldDto.fixture().copyWith(yield90d: 0), - YieldDto.fixture().copyWith(yield90d: 329087902), - ]; - - final yields = YieldsDto.fixture().copyWith(pools: pools); - - expect(yields.poolsSortedBy90dYield, pools.sorted((a, b) => b.yield90d.compareTo(a.yield90d))); - }); - - test("when calling 'poolsSortedByTimeframe' passing YieldTimeFrame.day it should return poolsSortedBy24hYield", () { - final pools = [ - YieldDto.fixture().copyWith(yield24h: 100), - YieldDto.fixture().copyWith(yield24h: 87), - YieldDto.fixture().copyWith(yield24h: 0), - YieldDto.fixture().copyWith(yield24h: 2000), - ]; - - final yields = YieldsDto.fixture().copyWith(pools: pools); - - expect(yields.poolsSortedByTimeframe(YieldTimeFrame.day), yields.poolsSortedBy24hYield); - }); - - test("when calling 'poolsSortedByTimeframe' passing YieldTimeFrame.week it should return poolsSortedBy7dYield", () { - final pools = [ - YieldDto.fixture().copyWith(yield7d: 12681), - YieldDto.fixture().copyWith(yield7d: 111), - YieldDto.fixture().copyWith(yield7d: 0), - YieldDto.fixture().copyWith(yield7d: 21971972891), - ]; - - final yields = YieldsDto.fixture().copyWith(pools: pools); - - expect(yields.poolsSortedByTimeframe(YieldTimeFrame.week), yields.poolsSortedBy7dYield); - }); - - test("when calling 'poolsSortedByTimeframe' passing YieldTimeFrame.month it should return poolsSortedBy30dYield", () { - final pools = [ - YieldDto.fixture().copyWith(yield30d: 089889888), - YieldDto.fixture().copyWith(yield30d: 2222), - YieldDto.fixture().copyWith(yield30d: 0), - YieldDto.fixture().copyWith(yield30d: 12615654), - ]; - - final yields = YieldsDto.fixture().copyWith(pools: pools); - - expect(yields.poolsSortedByTimeframe(YieldTimeFrame.month), yields.poolsSortedBy30dYield); - }); - - test( - "when calling 'poolsSortedByTimeframe' passing YieldTimeFrame.threeMonth it should return poolsSortedBy90dYield", - () { - final pools = [ - YieldDto.fixture().copyWith(yield90d: 978888), - YieldDto.fixture().copyWith(yield90d: 121), - YieldDto.fixture().copyWith(yield90d: 0), - YieldDto.fixture().copyWith(yield90d: 329087902), - ]; - - final yields = YieldsDto.fixture().copyWith(pools: pools); - - expect(yields.poolsSortedByTimeframe(YieldTimeFrame.threeMonth), yields.poolsSortedBy90dYield); - }, - ); -} diff --git a/test/core/enums/networks_test.dart b/test/core/enums/networks_test.dart index fbfd0d9..17dbbe9 100644 --- a/test/core/enums/networks_test.dart +++ b/test/core/enums/networks_test.dart @@ -373,7 +373,6 @@ void main() { ); }, ); - autoUpdateGoldenFiles = true; zGoldenTest( "Plasma network icon should be correct for dark mode (light icon)", goldenFileName: "plasma_network_icon_dark_mode", @@ -406,4 +405,68 @@ void main() { ); } }); + + test("websiteUrl extension should return the correct website for each network", () { + expect(AppNetworks.sepolia.websiteUrl, "https://ethereum.org", reason: "Sepolia website should match"); + expect(AppNetworks.mainnet.websiteUrl, "https://ethereum.org", reason: "Mainnet website should match"); + expect(AppNetworks.scroll.websiteUrl, "https://scroll.io", reason: "Scroll website should match"); + expect(AppNetworks.base.websiteUrl, "https://base.org", reason: "Base website should match"); + expect(AppNetworks.unichain.websiteUrl, "https://www.unichain.org", reason: "Unichain website should match"); + expect(AppNetworks.hyperEvm.websiteUrl, "https://hyperfoundation.org", reason: "HyperEVM website should match"); + expect(AppNetworks.plasma.websiteUrl, "https://www.plasma.to", reason: "Plasma website should match"); + }); + + test("websiteUrl should throw an error for allNetworks", () { + expect(() => AppNetworks.allNetworks.websiteUrl, throwsA(isA())); + }); + + test("dexscreenerUrl extension should return the correct dexscreener base URL for each network", () { + expect(AppNetworks.sepolia.dexscreenerUrl, null, reason: "Sepolia has no dexscreener URL"); + expect( + AppNetworks.mainnet.dexscreenerUrl, + "https://dexscreener.com/ethereum", + reason: "Mainnet dexscreener should match", + ); + expect( + AppNetworks.scroll.dexscreenerUrl, + "https://dexscreener.com/scroll", + reason: "Scroll dexscreener should match", + ); + expect(AppNetworks.base.dexscreenerUrl, "https://dexscreener.com/base", reason: "Base dexscreener should match"); + expect( + AppNetworks.unichain.dexscreenerUrl, + "https://dexscreener.com/unichain", + reason: "Unichain dexscreener should match", + ); + expect( + AppNetworks.hyperEvm.dexscreenerUrl, + "https://dexscreener.com/hyperevm", + reason: "HyperEVM dexscreener should match", + ); + expect( + AppNetworks.plasma.dexscreenerUrl, + "https://dexscreener.com/plasma", + reason: "Plasma dexscreener should match", + ); + }); + + test("dexscreenerUrl should return null for allNetworks", () { + expect(AppNetworks.allNetworks.dexscreenerUrl, null); + }); + + test("openAddress should open the correct address url for each network", () async { + const address = "0x1234567890abcdef1234567890abcdef12345678"; + + for (final network in AppNetworks.values) { + if (network.isAllNetworks) continue; + + await network.openAddress(address); + + expect( + UrlLauncherPlatformCustomMock.lastLaunchedUrl, + "${network.chainInfo.blockExplorerUrls?.first}/address/$address", + reason: "${network.name} should open the correct address URL", + ); + } + }); } diff --git a/test/core/enums/yield_timeframe_test.dart b/test/core/enums/pool_data_timeframe_test.dart similarity index 64% rename from test/core/enums/yield_timeframe_test.dart rename to test/core/enums/pool_data_timeframe_test.dart index 00a9b3c..3cf1bfc 100644 --- a/test/core/enums/yield_timeframe_test.dart +++ b/test/core/enums/pool_data_timeframe_test.dart @@ -1,36 +1,36 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; void main() { test("When calling 'isDay' and the timeframe is day, it should return true", () { - expect(YieldTimeFrame.day.isDay, true); + expect(PoolDataTimeframe.day.isDay, true); }); test("When calling 'isDay' and the timeframe is not day, it should return false", () { - expect(YieldTimeFrame.week.isDay, false); + expect(PoolDataTimeframe.week.isDay, false); }); test("When calling isWeek and the timeframe is week, it should return true", () { - expect(YieldTimeFrame.week.isWeek, true); + expect(PoolDataTimeframe.week.isWeek, true); }); test("When calling isWeek and the timeframe is not week, it should return false", () { - expect(YieldTimeFrame.day.isWeek, false); + expect(PoolDataTimeframe.day.isWeek, false); }); test("When calling isMonth and the timeframe is month, it should return true", () { - expect(YieldTimeFrame.month.isMonth, true); + expect(PoolDataTimeframe.month.isMonth, true); }); test("When calling isMonth and the timeframe is not month, it should return false", () { - expect(YieldTimeFrame.day.isMonth, false); + expect(PoolDataTimeframe.day.isMonth, false); }); test("When calling isThreeMonth and the timeframe is threeMonth, it should return true", () { - expect(YieldTimeFrame.threeMonth.isThreeMonth, true); + expect(PoolDataTimeframe.threeMonth.isThreeMonth, true); }); test("When calling isThreeMonth and the timeframe is not threeMonth, it should return false", () { - expect(YieldTimeFrame.day.isThreeMonth, false); + expect(PoolDataTimeframe.day.isThreeMonth, false); }); } diff --git a/test/core/extensions/num_extension_test.dart b/test/core/extensions/num_extension_test.dart index 348199d..555adcf 100644 --- a/test/core/extensions/num_extension_test.dart +++ b/test/core/extensions/num_extension_test.dart @@ -44,28 +44,36 @@ void main() { expect(number.toAmount(maxFixedDigits: 2), "123456789.12"); }); - test("if `useLessThan` is true on `toAmount` and the passed amount is less than 0.0001 it should return '<0.0001'", - () { - const number = 0.00001; + test( + "if `useLessThan` is true on `toAmount` and the passed amount is less than 0.0001 it should return '<0.0001'", + () { + const number = 0.00001; - expect(number.toAmount(useLessThan: true), "<0.0001"); - }); + expect(number.toAmount(useLessThan: true), "<0.0001"); + }, + ); - test(""""if `useLessThan` is true on `toAmount` and the passed amount is not less than 0.0001 + test( + """"if `useLessThan` is true on `toAmount` and the passed amount is not less than 0.0001 it should return it with fixed decimals of 4 (if none is passed) - """, () { - const number = 0.0143124; + """, + () { + const number = 0.0143124; - expect(number.toAmount(useLessThan: true), "0.0143"); - }); + expect(number.toAmount(useLessThan: true), "0.0143"); + }, + ); - test("""if `useLessThan` is true on `toAmount` and the passed amount + test( + """if `useLessThan` is true on `toAmount` and the passed amount is not less than 0.0001 it should return it with fixed decimals passed - """, () { - const number = 0.0143124; + """, + () { + const number = 0.0143124; - expect(number.toAmount(useLessThan: true, maxFixedDigits: 2), "0.01"); - }); + expect(number.toAmount(useLessThan: true, maxFixedDigits: 2), "0.01"); + }, + ); test("if the amount passed to `toAmount` is 0 it should return 0", () { const number = 0; @@ -73,20 +81,25 @@ void main() { expect(number.toAmount(), "0"); }); - test("When using `formatCompactCurrency`, it should return a string in the compact form (100k instead of 100,000)", - () { - const number = 123456; + test( + "When using `formatCompactCurrency`, it should return a string in the compact form (100k instead of 100,000)", + () { + const number = 123456; - expect(number.formatCompactCurrency(), "USD 123K"); - }); + expect(number.formatCompactCurrency(), "\$123K"); + }, + ); - test("""When using `formatCompactCurrency` with `isUSD` false, + test( + """When using `formatCompactCurrency` with `isUSD` false, it should return a string in the compact form - (100k instead of 100,000), but without the currency symbol""", () { - const number = 123456; + (100k instead of 100,000), but without the currency symbol""", + () { + const number = 123456; - expect(number.formatCompactCurrency(isUSD: false), "123K"); - }); + expect(number.formatCompactCurrency(isUSD: false), "123K"); + }, + ); test( """When passing `useMoreThan` true to `formatCompactCurrency`, @@ -108,12 +121,7 @@ void main() { () { final number = pow(10, 13) * 999; - expect( - number.formatCompactCurrency( - useMoreThan: true, - maxBeforeMoreThan: 1000, - ), - ">1K"); + expect(number.formatCompactCurrency(useMoreThan: true, maxBeforeMoreThan: 1000), ">1K"); }, ); @@ -123,14 +131,7 @@ void main() { it should return the passed number, but formated compactly """, () { - expect( - 1000.formatCompactCurrency( - useMoreThan: true, - maxBeforeMoreThan: 200000, - isUSD: false, - ), - "1K", - ); + expect(1000.formatCompactCurrency(useMoreThan: true, maxBeforeMoreThan: 200000, isUSD: false), "1K"); }, ); @@ -141,13 +142,7 @@ void main() { but formated compactly """, () { - expect( - 1000.formatCompactCurrency( - useMoreThan: true, - isUSD: false, - ), - "1K", - ); + expect(1000.formatCompactCurrency(useMoreThan: true, isUSD: false), "1K"); }, ); @@ -155,10 +150,7 @@ void main() { """`maybeFormatCompactCurrency` should format compact if the passed number is bigger than maxBeforeCompact""", () { - expect( - 1000.maybeFormatCompactCurrency(maxBeforeCompact: 999), - "USD 1K", - ); + expect(1000.maybeFormatCompactCurrency(maxBeforeCompact: 999), "\$1K"); }, ); @@ -166,13 +158,7 @@ void main() { """When `isUSD` is false in `maybeFormatCompactCurrency` should format compact if the passed number is bigger than maxBeforeCompact, but without the currency symbol""", () { - expect( - 1000.maybeFormatCompactCurrency( - maxBeforeCompact: 999, - isUSD: false, - ), - "1K", - ); + expect(1000.maybeFormatCompactCurrency(maxBeforeCompact: 999, isUSD: false), "1K"); }, ); @@ -180,14 +166,7 @@ void main() { """When `useMoreThan` is true in `maybeFormatCompactCurrency should format compact if the passed number is bigger than maxBeforeMoreThan`""", () { - expect( - 1000.maybeFormatCompactCurrency( - maxBeforeMoreThan: 999, - useMoreThan: true, - isUSD: false, - ), - ">999", - ); + expect(1000.maybeFormatCompactCurrency(maxBeforeMoreThan: 999, useMoreThan: true, isUSD: false), ">999"); }, ); @@ -196,10 +175,7 @@ void main() { and the passed number is less than 0.0001 should use `<` """, () { - expect( - 0.00001.maybeFormatCompactCurrency(useLessThan: true), - "<0.0001", - ); + expect(0.00001.maybeFormatCompactCurrency(useLessThan: true), "<0.0001"); }, ); } diff --git a/test/core/extensions/time_ago_extension_test.dart b/test/core/extensions/time_ago_extension_test.dart new file mode 100644 index 0000000..ff08149 --- /dev/null +++ b/test/core/extensions/time_ago_extension_test.dart @@ -0,0 +1,197 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:zup_app/core/extensions/time_ago_extension.dart'; +import 'package:zup_core/enums/time_unit.dart'; +import 'package:zup_core/objects/time_ago.dart'; + +import '../../golden_config.dart'; + +void main() { + Future widgetBuilder(TimeAgo timeAgo) => GoldenConfig.builder( + Builder( + builder: (context) { + return Text(timeAgo.formattedTimeAgo(context)); + }, + ), + ); + + testWidgets("When using formattedTimeAgo for milisseconds, it should use the correct string", (tester) async { + await tester.pumpWidget( + await widgetBuilder( + TimeAgo(amountTimeUnit: TimeUnit.milliseconds, amount: 10, remainder: 0, remainderTimeUnit: TimeUnit.hours), + ), + ); + + await tester.pumpAndSettle(); + + expect((find.byType(Text).evaluate().first.widget as Text).data, "10 milliseconds ago"); + }); + + testWidgets("When using formattedTimeAgo for seconds, it should use the correct string", (tester) async { + await tester.pumpWidget( + await widgetBuilder( + TimeAgo(amountTimeUnit: TimeUnit.seconds, amount: 55, remainder: 0, remainderTimeUnit: TimeUnit.hours), + ), + ); + + await tester.pumpAndSettle(); + + expect((find.byType(Text).evaluate().first.widget as Text).data, "55 seconds ago"); + }); + + testWidgets("When using formattedTimeAgo for minutes, with zero as remainder, it should only show the minutes ago", ( + tester, + ) async { + await tester.pumpWidget( + await widgetBuilder( + TimeAgo(amountTimeUnit: TimeUnit.minutes, amount: 55, remainder: 0, remainderTimeUnit: TimeUnit.seconds), + ), + ); + + await tester.pumpAndSettle(); + + expect((find.byType(Text).evaluate().first.widget as Text).data, "55 minutes ago"); + }); + + testWidgets( + "When using formattedTimeAgo for minutes, with non-zero as remainder, it should show the minutes and seconds ago", + (tester) async { + await tester.pumpWidget( + await widgetBuilder( + TimeAgo(amountTimeUnit: TimeUnit.minutes, amount: 55, remainder: 25, remainderTimeUnit: TimeUnit.seconds), + ), + ); + + await tester.pumpAndSettle(); + + expect((find.byType(Text).evaluate().first.widget as Text).data, "55 minutes and 25 seconds ago"); + }, + ); + + testWidgets( + "When using formattedTimeAgo for hours, with non-zero as remainder, it should show the hours and minutes ago", + (tester) async { + await tester.pumpWidget( + await widgetBuilder( + TimeAgo(amountTimeUnit: TimeUnit.hours, amount: 23, remainder: 54, remainderTimeUnit: TimeUnit.minutes), + ), + ); + + await tester.pumpAndSettle(); + + expect((find.byType(Text).evaluate().first.widget as Text).data, "23 hours and 54 minutes ago"); + }, + ); + + testWidgets( + """When using formattedTimeAgo for hours, with zero as remainder, + it should not show the minutes ago, only the hours""", + (tester) async { + await tester.pumpWidget( + await widgetBuilder( + TimeAgo(amountTimeUnit: TimeUnit.hours, amount: 23, remainder: 0, remainderTimeUnit: TimeUnit.minutes), + ), + ); + + await tester.pumpAndSettle(); + + expect((find.byType(Text).evaluate().first.widget as Text).data, "23 hours ago"); + }, + ); + + testWidgets( + """When using formattedTimeAgo for days, with zero as remainder, + it should not show the hours ago, only the days""", + (tester) async { + await tester.pumpWidget( + await widgetBuilder( + TimeAgo(amountTimeUnit: TimeUnit.days, amount: 11, remainder: 0, remainderTimeUnit: TimeUnit.hours), + ), + ); + + await tester.pumpAndSettle(); + + expect((find.byType(Text).evaluate().first.widget as Text).data, "11 days ago"); + }, + ); + + testWidgets( + """When using formattedTimeAgo for days, with non-zero as remainder, + it should show the days and hours ago""", + (tester) async { + await tester.pumpWidget( + await widgetBuilder( + TimeAgo(amountTimeUnit: TimeUnit.days, amount: 18, remainder: 22, remainderTimeUnit: TimeUnit.hours), + ), + ); + + await tester.pumpAndSettle(); + + expect((find.byType(Text).evaluate().first.widget as Text).data, "18 days and 22 hours ago"); + }, + ); + + testWidgets( + """When using formattedTimeAgo for months, with zero as remainder, + it should not show the days ago, only the months""", + (tester) async { + await tester.pumpWidget( + await widgetBuilder( + TimeAgo(amountTimeUnit: TimeUnit.months, amount: 11, remainder: 0, remainderTimeUnit: TimeUnit.days), + ), + ); + + await tester.pumpAndSettle(); + + expect((find.byType(Text).evaluate().first.widget as Text).data, "11 months ago"); + }, + ); + + testWidgets( + """When using formattedTimeAgo for months, with non-zero as remainder, + it should show the months and days ago""", + (tester) async { + await tester.pumpWidget( + await widgetBuilder( + TimeAgo(amountTimeUnit: TimeUnit.months, amount: 18, remainder: 22, remainderTimeUnit: TimeUnit.days), + ), + ); + + await tester.pumpAndSettle(); + + expect((find.byType(Text).evaluate().first.widget as Text).data, "18 months and 22 days ago"); + }, + ); + + testWidgets( + """When using formattedTimeAgo for years, with zero as remainder, + it should not show the months ago, only the years""", + (tester) async { + await tester.pumpWidget( + await widgetBuilder( + TimeAgo(amountTimeUnit: TimeUnit.years, amount: 11, remainder: 0, remainderTimeUnit: TimeUnit.months), + ), + ); + + await tester.pumpAndSettle(); + + expect((find.byType(Text).evaluate().first.widget as Text).data, "11 years ago"); + }, + ); + + testWidgets( + """When using formattedTimeAgo for years, with non-zero as remainder, + it should show the years and months ago""", + (tester) async { + await tester.pumpWidget( + await widgetBuilder( + TimeAgo(amountTimeUnit: TimeUnit.years, amount: 18, remainder: 22, remainderTimeUnit: TimeUnit.months), + ), + ); + + await tester.pumpAndSettle(); + + expect((find.byType(Text).evaluate().first.widget as Text).data, "18 years and 22 months ago"); + }, + ); +} diff --git a/test/core/pool_service_test.dart b/test/core/pool_service_test.dart index 5b6bd47..0117e52 100644 --- a/test/core/pool_service_test.dart +++ b/test/core/pool_service_test.dart @@ -17,9 +17,10 @@ import 'package:zup_app/abis/uniswap_v4_state_view.abi.g.dart'; import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_constants.dart'; import 'package:zup_app/core/concentrated_liquidity_utils/cl_pool_liquidity_calculations_mixin.dart'; import 'package:zup_app/core/concentrated_liquidity_utils/v4_pool_constants.dart'; +import 'package:zup_app/core/dtos/hook_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; import 'package:zup_app/core/dtos/protocol_dto.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/enums/pool_type.dart'; import 'package:zup_app/core/enums/protocol_id.dart'; @@ -39,7 +40,7 @@ void main() { late UniswapV4PositionManager positionManagerV4; late PancakeSwapInfinityClPoolManager pancakeSwapInfinityCLPoolManager; late Signer signer; - late YieldDto currentYield; + late LiquidityPoolDto currentYield; late TransactionResponse transactionResponse; late AerodromeV3PositionManager aerodromePositionManagerV3; late AerodromeV3Pool aerodromeV3Pool; @@ -101,7 +102,7 @@ void main() { aerodromeV3PoolImpl = AerodromeV3PoolImplMock(); pancakeSwapInfinityCLPositionManagerImpl = PancakeSwapInfinityCLPositionManagerImplMock(); - currentYield = YieldDto.fixture().copyWith( + currentYield = LiquidityPoolDto.fixture().copyWith( protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.unknown, rawId: "1"), ); @@ -261,8 +262,8 @@ void main() { final currentYield0 = currentYield.copyWith( poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: EthereumConstants.zeroAddress}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x123"}), + token0: SingleChainTokenDto.fixture().copyWith(address: EthereumConstants.zeroAddress), + token1: SingleChainTokenDto.fixture().copyWith(address: "0x123"), ); when(() => positionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); @@ -317,8 +318,8 @@ void main() { final currentYield0 = currentYield.copyWith( poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => positionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); @@ -385,8 +386,8 @@ void main() { final currentYield0 = currentYield.copyWith( poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => positionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); @@ -453,8 +454,8 @@ void main() { final currentYield0 = currentYield.copyWith( poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => positionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); @@ -509,8 +510,8 @@ void main() { final currentYield0 = currentYield.copyWith( poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => positionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); @@ -571,8 +572,8 @@ void main() { initialFeeTier: 3982, poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); final amount0Desired = BigInt.from(4311); @@ -642,8 +643,8 @@ void main() { chainId: network.chainId, poolType: PoolType.v4, v4StateView: "0x1", - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: EthereumConstants.zeroAddress}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x1"}), + token0: SingleChainTokenDto.fixture().copyWith(address: EthereumConstants.zeroAddress), + token1: SingleChainTokenDto.fixture().copyWith(address: "0x1"), ); await sut.sendV4PoolDepositTransaction( @@ -696,8 +697,8 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: EthereumConstants.zeroAddress}), - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x1"}), + token1: SingleChainTokenDto.fixture().copyWith(address: EthereumConstants.zeroAddress), + token0: SingleChainTokenDto.fixture().copyWith(address: "0x1"), ); await sut.sendV4PoolDepositTransaction( @@ -750,8 +751,8 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x2"}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x1"}), + token0: SingleChainTokenDto.fixture().copyWith(address: "0x2"), + token1: SingleChainTokenDto.fixture().copyWith(address: "0x1"), ); await sut.sendV4PoolDepositTransaction( @@ -807,8 +808,8 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), ); await sut.sendV4PoolDepositTransaction( @@ -841,7 +842,7 @@ void main() { token1Address, BigInt.from(currentYield0.initialFeeTier), BigInt.from(currentYield0.tickSpacing), - currentYield0.v4Hooks, + EthereumConstants.zeroAddress, ], tickLower, tickUpper, @@ -909,11 +910,11 @@ void main() { final currentYield0 = currentYield.copyWith( chainId: network.chainId, v4PoolManager: poolManager, - v4Hooks: hooks, + hook: HookDto.fixture().copyWith(address: hooks), poolType: PoolType.v4, protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), ); await sut.sendV4PoolDepositTransaction( @@ -1009,11 +1010,11 @@ void main() { final currentYield0 = currentYield.copyWith( chainId: network.chainId, v4PoolManager: poolManager, - v4Hooks: hooks, + hook: HookDto.fixture().copyWith(address: hooks), poolType: PoolType.v4, protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), ); await sut.sendV4PoolDepositTransaction( @@ -1090,11 +1091,11 @@ void main() { final currentYield0 = currentYield.copyWith( chainId: network.chainId, v4PoolManager: poolManager, - v4Hooks: hooks, + hook: HookDto.fixture().copyWith(address: hooks), poolType: PoolType.v4, protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), ); await sut.sendV4PoolDepositTransaction( @@ -1169,11 +1170,11 @@ void main() { final currentYield0 = currentYield.copyWith( chainId: network.chainId, v4PoolManager: poolManager, - v4Hooks: hooks, + hook: HookDto.fixture().copyWith(address: hooks), poolType: PoolType.v4, protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), ); await sut.sendV4PoolDepositTransaction( @@ -1220,8 +1221,8 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), ); await sut.sendV4PoolDepositTransaction( @@ -1267,8 +1268,8 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), ); await sut.sendV4PoolDepositTransaction( @@ -1316,8 +1317,8 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); await sut.sendV4PoolDepositTransaction( @@ -1362,8 +1363,8 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => ethereumAbiCoder.encodePacked(["uint8", "uint8", "uint8"], any())).thenReturn(actionsEncoded); @@ -1473,8 +1474,8 @@ void main() { poolType: PoolType.v4, v4PoolManager: "0xbvv", protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => ethereumAbiCoder.encodePacked(["uint8", "uint8", "uint8"], any())).thenReturn(actionsEncoded); @@ -1580,8 +1581,8 @@ void main() { poolType: PoolType.v4, v4PoolManager: "0xbvv", protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => ethereumAbiCoder.encodePacked(["uint8", "uint8", "uint8"], any())).thenReturn(actionsEncoded); @@ -1665,8 +1666,8 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => ethereumAbiCoder.encodePacked(["uint8", "uint8", "uint8"], any())).thenReturn(actionsEncoded); @@ -1753,8 +1754,8 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => ethereumAbiCoder.encodePacked(["uint8", "uint8"], any())).thenReturn(actionsEncoded); @@ -1833,8 +1834,8 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); @@ -1888,8 +1889,8 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); @@ -1943,8 +1944,8 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); @@ -1998,8 +1999,8 @@ void main() { chainId: network.chainId, v4StateView: "0x1", poolType: PoolType.v4, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => ethereumAbiCoder.encodePacked(any(), any())).thenReturn("0x"); @@ -2193,7 +2194,7 @@ void main() { token1: "", )); - registerFallbackValue(YieldDto.fixture()); + registerFallbackValue(LiquidityPoolDto.fixture()); when( () => aerodromePositionManagerV3.fromSigner( @@ -2414,8 +2415,8 @@ void main() { protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: EthereumConstants.zeroAddress}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x123"}), + token0: SingleChainTokenDto.fixture().copyWith(address: EthereumConstants.zeroAddress), + token1: SingleChainTokenDto.fixture().copyWith(address: "0x123"), ); when(() => aerodromePositionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); @@ -2469,8 +2470,8 @@ void main() { protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when( @@ -2540,8 +2541,8 @@ void main() { protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when( @@ -2609,8 +2610,8 @@ void main() { protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => aerodromePositionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); @@ -2663,8 +2664,8 @@ void main() { protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.aerodromeSlipstream), poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => aerodromePositionManagerV3.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); @@ -2725,8 +2726,8 @@ void main() { initialFeeTier: 3982, poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); final amount0Desired = BigInt.from(4311); @@ -2805,8 +2806,8 @@ void main() { initialFeeTier: 3982, poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); final amount0Desired = BigInt.from(4311); @@ -2874,8 +2875,8 @@ void main() { initialFeeTier: 3982, poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); final amount0Desired = BigInt.from(4311); @@ -3123,8 +3124,8 @@ void main() { protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: EthereumConstants.zeroAddress}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: "0x123"}), + token0: SingleChainTokenDto.fixture().copyWith(address: EthereumConstants.zeroAddress), + token1: SingleChainTokenDto.fixture().copyWith(address: "0x123"), ); when(() => algebra121PositionManager.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); @@ -3178,8 +3179,8 @@ void main() { protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => algebra121PositionManager.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); @@ -3247,8 +3248,8 @@ void main() { protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => algebra121PositionManager.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); @@ -3313,8 +3314,8 @@ void main() { protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), ); when(() => algebra121PositionManager.getMintCalldata(params: any(named: "params"))).thenReturn(mintCalldata); @@ -3369,8 +3370,8 @@ void main() { protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), deployerAddress: expectedDeployer, ); @@ -3425,8 +3426,8 @@ void main() { protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), deployerAddress: expectedDeployer, ); @@ -3476,8 +3477,8 @@ void main() { protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), deployerAddress: expectedDeployer, ); @@ -3531,8 +3532,8 @@ void main() { protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.gliquidV3), poolType: PoolType.v3, chainId: network.chainId, - token0: TokenDto.fixture().copyWith(addresses: {network.chainId: token0Address}), - token1: TokenDto.fixture().copyWith(addresses: {network.chainId: token1Address}), + token0: SingleChainTokenDto.fixture().copyWith(address: token0Address), + token1: SingleChainTokenDto.fixture().copyWith(address: token1Address), deployerAddress: EthereumConstants.zeroAddress, ); @@ -3696,11 +3697,11 @@ void main() { ], [ [ - currentYield.token0.addresses[currentYield.network.chainId]!, - currentYield.token1.addresses[currentYield.network.chainId]!, + currentYield.token0.address, + currentYield.token1.address, BigInt.from(currentYield.initialFeeTier), BigInt.from(currentYield.tickSpacing), - currentYield.v4Hooks, + EthereumConstants.zeroAddress, ], tickLower, tickUpper, @@ -3770,7 +3771,7 @@ void main() { currentYield.copyWith( protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL), poolType: PoolType.v4, - v4Hooks: hooks, + hook: HookDto.fixture().copyWith(address: hooks), v4PoolManager: "0x", v4StateView: "0x", ), @@ -3798,8 +3799,8 @@ void main() { ], [ [ - currentYield.token0.addresses[currentYield.network.chainId]!, - currentYield.token1.addresses[currentYield.network.chainId]!, + currentYield.token0.address, + currentYield.token1.address, hooks, poolManager, currentYield.initialFeeTier, diff --git a/test/core/repositories/tokens_repository_test.dart b/test/core/repositories/tokens_repository_test.dart index 64ea073..aa4cbc8 100644 --- a/test/core/repositories/tokens_repository_test.dart +++ b/test/core/repositories/tokens_repository_test.dart @@ -1,7 +1,8 @@ import 'package:dio/dio.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; import 'package:zup_app/core/dtos/token_list_dto.dart'; import 'package:zup_app/core/dtos/token_price_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; @@ -18,7 +19,7 @@ void main() { sut = TokensRepository(dio); }); - test("When calling `searchToken` it should call the correct endpoint", () async { + test("When calling `searchToken` passing a query and a network it should call the correct endpoint", () async { const query = "dale"; const network = AppNetworks.sepolia; @@ -29,21 +30,22 @@ void main() { cancelToken: any(named: "cancelToken"), ), ).thenAnswer( - (_) async => Response(data: [TokenDto.fixture().toJson()], statusCode: 200, requestOptions: RequestOptions()), + (_) async => + Response(data: [SingleChainTokenDto.fixture().toJson()], statusCode: 200, requestOptions: RequestOptions()), ); await sut.searchToken(query, network); verify( () => dio.get( - "/tokens/search", + "/tokens/search/${network.chainId}", cancelToken: any(named: "cancelToken"), - queryParameters: {"chainId": network.chainId, "query": query}, + queryParameters: {"query": query}, ), ); }); - test("When calling 'searchToken' and the network is all networks, it should not pass the chainId param", () async { + test("When calling 'searchToken' and the network is all networks, it should call the correct endpoint", () async { const query = "dale"; when( @@ -53,22 +55,39 @@ void main() { cancelToken: any(named: "cancelToken"), ), ).thenAnswer( - (_) async => Response(data: [TokenDto.fixture().toJson()], statusCode: 200, requestOptions: RequestOptions()), + (_) async => + Response(data: [MultiChainTokenDto.fixture().toJson()], statusCode: 200, requestOptions: RequestOptions()), ); await sut.searchToken(query, AppNetworks.allNetworks); verify( () => dio.get( - "/tokens/search", + "/tokens/search/all", cancelToken: any(named: "cancelToken"), queryParameters: {"query": query}, ), ); }); - test("When calling `searchToken` it should correctly parse the response", () async { - final tokens = [TokenDto.fixture(), TokenDto.fixture(), TokenDto.fixture()]; + test("When calling `searchToken` for a specific network it should correctly parse the response", () async { + final tokensResponse = [ + SingleChainTokenDto.fixture().toJson(), + SingleChainTokenDto.fixture().toJson(), + SingleChainTokenDto.fixture().toJson(), + ]; + + final expectedParsedTokens = tokensResponse + .map( + (token) => MultiChainTokenDto( + addresses: {AppNetworks.sepolia.chainId: token["address"]}, + decimals: {AppNetworks.sepolia.chainId: token["decimals"]}, + logoUrl: token["logoUrl"], + name: token["name"], + symbol: token["symbol"], + ), + ) + .toList(); when( () => dio.get( @@ -76,17 +95,11 @@ void main() { queryParameters: any(named: "queryParameters"), cancelToken: any(named: "cancelToken"), ), - ).thenAnswer( - (_) async => Response( - data: [TokenDto.fixture().toJson(), TokenDto.fixture().toJson(), TokenDto.fixture().toJson()], - statusCode: 200, - requestOptions: RequestOptions(), - ), - ); + ).thenAnswer((_) async => Response(data: tokensResponse, statusCode: 200, requestOptions: RequestOptions())); final response = await sut.searchToken("query", AppNetworks.sepolia); - expect(response, tokens); + expect(response, expectedParsedTokens); }); test( @@ -127,7 +140,7 @@ void main() { await sut.getTokenPrice(address, network); - verify(() => dio.get("/tokens/price", queryParameters: {"address": address, "chainId": network.chainId})).called(1); + verify(() => dio.get("/tokens/$address/${network.chainId}/price")).called(1); }); test("When calling `getTokenPrice` it should correctly parse the response", () async { diff --git a/test/core/repositories/yield_repository_test.dart b/test/core/repositories/yield_repository_test.dart index c2e5d57..2f5a2b4 100644 --- a/test/core/repositories/yield_repository_test.dart +++ b/test/core/repositories/yield_repository_test.dart @@ -1,8 +1,8 @@ import 'package:dio/dio.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; +import 'package:zup_app/core/dtos/liquidity_pools_search_result_dto.dart'; import 'package:zup_app/core/dtos/pool_search_settings_dto.dart'; -import 'package:zup_app/core/dtos/yields_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/repositories/yield_repository.dart'; @@ -18,7 +18,7 @@ void main() { }); test("When calling `getSingleNetworkYield` it should call the correct endpoint with the correct params", () async { - final yields = YieldsDto.fixture(); + final yields = LiquidityPoolsSearchResultDto.fixture(); when( () => dio.post( @@ -60,107 +60,14 @@ void main() { "group1Id": group1Id, }, data: { - "filters": { - "minTvlUsd": searchSettings.minLiquidityUSD, - "blockedProtocols": blockedProtocolsIds, - "allowedPoolTypes": ["V3", "V4"], - }, - }, - ), - ).called(1); - }); - - test("When the V3 Pool is disabled in the search settings, it should not be included in the request", () async { - final yields = YieldsDto.fixture(); - - when( - () => dio.post( - any(), - queryParameters: any(named: "queryParameters"), - data: any(named: "data"), - ), - ).thenAnswer( - (_) async => Response(data: {"bestYields": yields.toJson()}, statusCode: 200, requestOptions: RequestOptions()), - ); - - const token0Address = "0x123"; - const token1Address = "0x456"; - const network = AppNetworks.sepolia; - final searchSettings = PoolSearchSettingsDto.fixture().copyWith(allowV3Search: false); - final blockedProtocolsIds = ["1", "2", "3"]; - - await sut.getSingleNetworkYield( - group0Id: null, - group1Id: null, - blockedProtocolIds: blockedProtocolsIds, - token0Address: token0Address, - token1Address: token1Address, - - network: network, - searchSettings: searchSettings, - ); - - verify( - () => dio.post( - "/pools/search/${network.chainId}", - queryParameters: {"token0Address": token0Address, "token1Address": token1Address}, - data: { - "filters": { - "minTvlUsd": searchSettings.minLiquidityUSD, - "blockedProtocols": blockedProtocolsIds, - "allowedPoolTypes": ["V4"], - }, - }, - ), - ).called(1); - }); - - test("When the V4 Pool is disabled in the search settings, it should not be included in the request", () async { - final yields = YieldsDto.fixture(); - - when( - () => dio.post( - any(), - queryParameters: any(named: "queryParameters"), - data: any(named: "data"), - ), - ).thenAnswer( - (_) async => Response(data: {"bestYields": yields.toJson()}, statusCode: 200, requestOptions: RequestOptions()), - ); - - const token0Address = "0x123"; - const token1Address = "0x456"; - const network = AppNetworks.sepolia; - final searchSettings = PoolSearchSettingsDto.fixture().copyWith(allowV4Search: false); - final blockedProtocolIds = ["1", "2", "3"]; - - await sut.getSingleNetworkYield( - group0Id: null, - group1Id: null, - blockedProtocolIds: blockedProtocolIds, - token0Address: token0Address, - token1Address: token1Address, - network: network, - searchSettings: searchSettings, - ); - - verify( - () => dio.post( - "/pools/search/${network.chainId}", - queryParameters: {"token0Address": token0Address, "token1Address": token1Address}, - data: { - "filters": { - "blockedProtocols": blockedProtocolIds, - "minTvlUsd": searchSettings.minLiquidityUSD, - "allowedPoolTypes": ["V3"], - }, + "filters": {"minimumTvlUsd": searchSettings.minLiquidityUSD, "blockedProtocols": blockedProtocolsIds}, }, ), ).called(1); }); test("When calling `getYields` it should correctly parse the response", () async { - final yields = YieldsDto.fixture(); + final yields = LiquidityPoolsSearchResultDto.fixture(); when( () => dio.post( @@ -188,7 +95,7 @@ void main() { }); test("when calling 'getAllNetworksYield' it should call the correct endpoint with the correct params", () async { - final yields = YieldsDto.fixture(); + final yields = LiquidityPoolsSearchResultDto.fixture(); when( () => dio.post( @@ -223,115 +130,15 @@ void main() { "/pools/search/all", queryParameters: {"token0Id": token0Id, "token1Id": token1Id, "group0Id": group0Id, "group1Id": group1Id}, data: { - "filters": { - "testnetMode": true, - "minTvlUsd": searchSettings.minLiquidityUSD, - "blockedProtocols": blockedProtocolsIds, - "allowedPoolTypes": ["V3", "V4"], - }, + "filters": {"minimumTvlUsd": searchSettings.minLiquidityUSD, "blockedProtocols": blockedProtocolsIds}, + "config": {"testnetMode": true}, }, ), ).called(1); }); - test( - "when calling 'getAllNetworksYield' and the search settings has the v4 pool disallowed, it should not be included in the params", - () async { - final yields = YieldsDto.fixture(); - - when( - () => dio.post( - any(), - queryParameters: any(named: "queryParameters"), - data: any(named: "data"), - ), - ).thenAnswer( - (_) async => Response(data: {"bestYields": yields.toJson()}, statusCode: 200, requestOptions: RequestOptions()), - ); - - const token0Id = "0x123"; - const token1Id = "0x456"; - const minTvlUsd = 1213; - final searchSettings = PoolSearchSettingsDto.fixture().copyWith(minLiquidityUSD: minTvlUsd, allowV4Search: false); - final blockedProtocolsIds = ["ai", "be", "cd"]; - - await sut.getAllNetworksYield( - group0Id: null, - group1Id: null, - blockedProtocolIds: blockedProtocolsIds, - token0InternalId: token0Id, - token1InternalId: token1Id, - searchSettings: searchSettings, - testnetMode: true, - ); - - verify( - () => dio.post( - "/pools/search/all", - queryParameters: {"token0Id": token0Id, "token1Id": token1Id}, - data: { - "filters": { - "testnetMode": true, - "minTvlUsd": searchSettings.minLiquidityUSD, - "blockedProtocols": blockedProtocolsIds, - "allowedPoolTypes": ["V3"], - }, - }, - ), - ).called(1); - }, - ); - - test( - "when calling 'getAllNetworksYield' and the search settings has the v3 pool disallowed, it should not be included in the params", - () async { - final yields = YieldsDto.fixture(); - - when( - () => dio.post( - any(), - queryParameters: any(named: "queryParameters"), - data: any(named: "data"), - ), - ).thenAnswer( - (_) async => Response(data: {"bestYields": yields.toJson()}, statusCode: 200, requestOptions: RequestOptions()), - ); - - const token0Id = "0x123"; - const token1Id = "0x456"; - const minTvlUsd = 1213; - final searchSettings = PoolSearchSettingsDto.fixture().copyWith(minLiquidityUSD: minTvlUsd, allowV3Search: false); - final blockedProtocolsIds = ["ai", "be", "cd"]; - - await sut.getAllNetworksYield( - group0Id: null, - group1Id: null, - blockedProtocolIds: blockedProtocolsIds, - token0InternalId: token0Id, - token1InternalId: token1Id, - searchSettings: searchSettings, - testnetMode: true, - ); - - verify( - () => dio.post( - "/pools/search/all", - queryParameters: {"token0Id": token0Id, "token1Id": token1Id}, - data: { - "filters": { - "testnetMode": true, - "minTvlUsd": searchSettings.minLiquidityUSD, - "blockedProtocols": blockedProtocolsIds, - "allowedPoolTypes": ["V4"], - }, - }, - ), - ).called(1); - }, - ); - test("when calling 'getAllNetworksYield' it should correctly parse the response", () async { - final yields = YieldsDto.fixture(); + final yields = LiquidityPoolsSearchResultDto.fixture(); when( () => dio.post( diff --git a/test/core/zup_analytics_test.dart b/test/core/zup_analytics_test.dart index 90ebe9e..e79165b 100644 --- a/test/core/zup_analytics_test.dart +++ b/test/core/zup_analytics_test.dart @@ -1,8 +1,8 @@ import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; import 'package:zup_app/core/dtos/token_price_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/repositories/tokens_repository.dart'; import 'package:zup_app/core/zup_analytics.dart'; @@ -30,7 +30,7 @@ void main() { }); test("when calling `logDeposit` it should log the event with the correct name and params", () async { - final depositedYield = YieldDto.fixture(); + final depositedYield = LiquidityPoolDto.fixture(); const amount0 = 1.0; const amount1 = 2.0; @@ -39,10 +39,10 @@ void main() { final token1Price = TokenPriceDto.fixture().copyWith(usdPrice: 21); when( - () => tokensRepository.getTokenPrice(depositedYield.token0.addresses[depositedYield.network.chainId]!, any()), + () => tokensRepository.getTokenPrice(depositedYield.token0.address, any()), ).thenAnswer((_) async => token0Price); when( - () => tokensRepository.getTokenPrice(depositedYield.token1.addresses[depositedYield.network.chainId]!, any()), + () => tokensRepository.getTokenPrice(depositedYield.token1.address, any()), ).thenAnswer((_) async => token1Price); await sut.logDeposit( @@ -56,8 +56,8 @@ void main() { () => firebaseAnalytics.logEvent( name: "user_deposited", parameters: { - "token0_address": "hex:${depositedYield.token0.addresses[depositedYield.network.chainId]!}", - "token1_address": "hex:${depositedYield.token1.addresses[depositedYield.network.chainId]!}", + "token0_address": "hex:${depositedYield.token0.address}", + "token1_address": "hex:${depositedYield.token1.address}", "amount0": amount0, "amount1": amount1, "network": depositedYield.network.label, @@ -102,7 +102,7 @@ void main() { ).thenThrow(Exception()); await sut.logDeposit( - depositedYield: YieldDto.fixture(), + depositedYield: LiquidityPoolDto.fixture(), amount0Formatted: 1.0, amount1Formatted: 1.0, walletAddress: "0x123", diff --git a/test/core/zup_navigator_test.dart b/test/core/zup_navigator_test.dart index 7f45586..4c0f978 100644 --- a/test/core/zup_navigator_test.dart +++ b/test/core/zup_navigator_test.dart @@ -3,9 +3,9 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:routefly/routefly.dart'; import 'package:web3kit/web3kit.dart'; import 'package:zup_app/core/dtos/deposit_page_arguments_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; import 'package:zup_app/core/enums/zup_navigator_paths.dart'; import 'package:zup_app/core/zup_navigator.dart'; import 'package:zup_app/core/zup_route_params_names.dart'; @@ -233,8 +233,8 @@ void main() { runApp(material); const network = AppNetworks.mainnet; - final yieldPool = YieldDto.fixture().copyWith(chainId: network.chainId); - const yieldTimeFrame = YieldTimeFrame.month; + final yieldPool = LiquidityPoolDto.fixture().copyWith(chainId: network.chainId); + const yieldTimeFrame = PoolDataTimeframe.month; const parseWrappedToNative = true; await ZupNavigator().navigateToDeposit( @@ -255,8 +255,8 @@ void main() { runApp(material); const network = AppNetworks.mainnet; - final yieldPool = YieldDto.fixture().copyWith(chainId: network.chainId, poolAddress: "xabasRAaa"); - const yieldTimeFrame = YieldTimeFrame.month; + final yieldPool = LiquidityPoolDto.fixture().copyWith(chainId: network.chainId, poolAddress: "xabasRAaa"); + const yieldTimeFrame = PoolDataTimeframe.month; const parseWrappedToNative = true; await ZupNavigator().navigateToDeposit( @@ -271,8 +271,11 @@ void main() { testWidgets("When calling `navigateToDeposit` it should pass the pool dto as argument", (tester) async { await tester.pumpWidget(material); - final yieldPool = YieldDto.fixture().copyWith(chainId: AppNetworks.mainnet.chainId, poolAddress: "Pull Address"); - const yieldTimeFrame = YieldTimeFrame.month; + final yieldPool = LiquidityPoolDto.fixture().copyWith( + chainId: AppNetworks.mainnet.chainId, + poolAddress: "Pull Address", + ); + const yieldTimeFrame = PoolDataTimeframe.month; const parseWrappedToNative = true; await ZupNavigator().navigateToDeposit( diff --git a/test/mocks.dart b/test/mocks.dart index 47facf7..90fa584 100644 --- a/test/mocks.dart +++ b/test/mocks.dart @@ -30,7 +30,6 @@ import 'package:zup_app/app/create/yields/yields_cubit.dart'; import 'package:zup_app/core/cache.dart'; import 'package:zup_app/core/debouncer.dart'; import 'package:zup_app/core/pool_service.dart'; -import 'package:zup_app/core/repositories/positions_repository.dart'; import 'package:zup_app/core/repositories/protocol_repository.dart'; import 'package:zup_app/core/repositories/tokens_repository.dart'; import 'package:zup_app/core/repositories/yield_repository.dart'; @@ -39,8 +38,8 @@ import 'package:zup_app/core/zup_links.dart'; import 'package:zup_app/core/zup_navigator.dart'; import 'package:zup_app/gen/assets.gen.dart'; import 'package:zup_app/widgets/token_selector_modal/token_selector_modal_cubit.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; import 'package:zup_core/zup_core.dart'; +import 'package:zup_ui_kit/zup_ui_kit.dart'; class $AssetsLottiesGenMock extends Mock implements $AssetsLottiesGen {} @@ -62,8 +61,6 @@ class ImageProviderMock extends Mock implements ImageProvider {} class ListenableMock extends Mock implements Listenable {} -class PositionsRepositoryMock extends Mock implements PositionsRepository {} - class SharedPreferencesWithCacheMock extends Mock implements SharedPreferencesWithCache {} class SignerMock extends Mock implements Signer {} @@ -118,7 +115,7 @@ class WalletMock extends Mock implements Wallet {} class YieldRepositoryMock extends Mock implements YieldRepository {} -class ZupCachedImageMock extends Mock implements ZupCachedImage {} +class ZupNetworkImageMock extends Mock implements ZupNetworkImage {} class ZupNavigatorMock extends Mock implements ZupNavigator {} @@ -157,6 +154,10 @@ class ZupAnalyticsMock extends Mock implements ZupAnalytics {} class UrlLauncherPlatformCustomMock extends UrlLauncherPlatform { static String? lastLaunchedUrl; + UrlLauncherPlatformCustomMock() { + lastLaunchedUrl = null; + } + @override LinkDelegate? get linkDelegate => null; @@ -198,23 +199,22 @@ T mockHttpImage(T Function() on, {Uint8List? overrideImage}) { return mockNetworkImages(on, imageBytes: overrideImage); } -ZupCachedImage mockZupCachedImage() { - final zupCachedImage = ZupCachedImageMock(); - final context = BuildContextMock(); - registerFallbackValue(context); +ZupNetworkImage mockZupNetworkImage() { + final zupNetworkImage = ZupNetworkImageMock(); + registerFallbackValue(BuildContextMock()); when( - () => zupCachedImage.build( + () => zupNetworkImage.load( any(), any(), height: any(named: "height"), width: any(named: "width"), - radius: any(named: "radius"), + backgroundColor: any(named: "backgroundColor"), errorWidget: any(named: "errorWidget"), placeholder: any(named: "placeholder"), - backgroundColor: any(named: "backgroundColor"), + radius: any(named: "radius"), ), - ).thenReturn(const SizedBox(child: Text("IMAGE"))); + ).thenReturn(const Text("IMAGE")); - return zupCachedImage; + return zupNetworkImage; } diff --git a/test/widgets/goldens/pool_info_modal_24h_initial.png b/test/widgets/goldens/pool_info_modal_24h_initial.png new file mode 100644 index 0000000..60b72dc Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_24h_initial.png differ diff --git a/test/widgets/goldens/pool_info_modal_30d_initial.png b/test/widgets/goldens/pool_info_modal_30d_initial.png new file mode 100644 index 0000000..d663099 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_30d_initial.png differ diff --git a/test/widgets/goldens/pool_info_modal_7d_initial.png b/test/widgets/goldens/pool_info_modal_7d_initial.png new file mode 100644 index 0000000..e168a7a Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_7d_initial.png differ diff --git a/test/widgets/goldens/pool_info_modal_90d_initial.png b/test/widgets/goldens/pool_info_modal_90d_initial.png new file mode 100644 index 0000000..e5d7130 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_90d_initial.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_fee_tier_tooltip.png b/test/widgets/goldens/pool_info_modal_about_tab_fee_tier_tooltip.png new file mode 100644 index 0000000..896908a Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_fee_tier_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_fee_tier_tooltip_mobile.png b/test/widgets/goldens/pool_info_modal_about_tab_fee_tier_tooltip_mobile.png new file mode 100644 index 0000000..0a14a56 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_fee_tier_tooltip_mobile.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_hooks_tooltip_mobile.png b/test/widgets/goldens/pool_info_modal_about_tab_hooks_tooltip_mobile.png new file mode 100644 index 0000000..ab23275 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_hooks_tooltip_mobile.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_pool_type_tooltip_mobile.png b/test/widgets/goldens/pool_info_modal_about_tab_pool_type_tooltip_mobile.png new file mode 100644 index 0000000..ddefad1 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_pool_type_tooltip_mobile.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_switch.png b/test/widgets/goldens/pool_info_modal_about_tab_switch.png new file mode 100644 index 0000000..e8b2960 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_switch.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_token_0_copied_tooltip.png b/test/widgets/goldens/pool_info_modal_about_tab_token_0_copied_tooltip.png new file mode 100644 index 0000000..4fb7073 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_token_0_copied_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_token_0_copy_tooltip.png b/test/widgets/goldens/pool_info_modal_about_tab_token_0_copy_tooltip.png new file mode 100644 index 0000000..b9cd590 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_token_0_copy_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_token_0_native.png b/test/widgets/goldens/pool_info_modal_about_tab_token_0_native.png new file mode 100644 index 0000000..35c1885 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_token_0_native.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_token_1_copied_tooltip.png b/test/widgets/goldens/pool_info_modal_about_tab_token_1_copied_tooltip.png new file mode 100644 index 0000000..3e6243b Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_token_1_copied_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_token_1_copy_tooltip.png b/test/widgets/goldens/pool_info_modal_about_tab_token_1_copy_tooltip.png new file mode 100644 index 0000000..24da1e3 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_token_1_copy_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_token_1_native.png b/test/widgets/goldens/pool_info_modal_about_tab_token_1_native.png new file mode 100644 index 0000000..11d6205 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_token_1_native.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_v3_pool_type_tooltip.png b/test/widgets/goldens/pool_info_modal_about_tab_v3_pool_type_tooltip.png new file mode 100644 index 0000000..a0db88a Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_v3_pool_type_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_v4_hooks_address.png b/test/widgets/goldens/pool_info_modal_about_tab_v4_hooks_address.png new file mode 100644 index 0000000..51c62ca Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_v4_hooks_address.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_v4_hooks_copied_tooltip.png b/test/widgets/goldens/pool_info_modal_about_tab_v4_hooks_copied_tooltip.png new file mode 100644 index 0000000..c3c25f9 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_v4_hooks_copied_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_v4_hooks_copy_tooltip.png b/test/widgets/goldens/pool_info_modal_about_tab_v4_hooks_copy_tooltip.png new file mode 100644 index 0000000..ac07167 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_v4_hooks_copy_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_v4_hooks_tooltip.png b/test/widgets/goldens/pool_info_modal_about_tab_v4_hooks_tooltip.png new file mode 100644 index 0000000..d5d8757 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_v4_hooks_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_about_tab_v4_pool_type_tooltip.png b/test/widgets/goldens/pool_info_modal_about_tab_v4_pool_type_tooltip.png new file mode 100644 index 0000000..f4f61b5 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_about_tab_v4_pool_type_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_add_liquidity_pop.png b/test/widgets/goldens/pool_info_modal_add_liquidity_pop.png new file mode 100644 index 0000000..ae1eed3 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_add_liquidity_pop.png differ diff --git a/test/widgets/goldens/pool_info_modal_copy_pool_address_tooltip.png b/test/widgets/goldens/pool_info_modal_copy_pool_address_tooltip.png new file mode 100644 index 0000000..b9c4cc3 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_copy_pool_address_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_copy_pool_address_tooltip_copied.png b/test/widgets/goldens/pool_info_modal_copy_pool_address_tooltip_copied.png new file mode 100644 index 0000000..e806f5a Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_copy_pool_address_tooltip_copied.png differ diff --git a/test/widgets/goldens/pool_info_modal_dynamic_fee.png b/test/widgets/goldens/pool_info_modal_dynamic_fee.png new file mode 100644 index 0000000..ca33150 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_dynamic_fee.png differ diff --git a/test/widgets/goldens/pool_info_modal_fees_tooltip.png b/test/widgets/goldens/pool_info_modal_fees_tooltip.png new file mode 100644 index 0000000..b231cd2 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_fees_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_fees_tooltip_mobile.png b/test/widgets/goldens/pool_info_modal_fees_tooltip_mobile.png new file mode 100644 index 0000000..23a6359 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_fees_tooltip_mobile.png differ diff --git a/test/widgets/goldens/pool_info_modal_negative_net_inflow.png b/test/widgets/goldens/pool_info_modal_negative_net_inflow.png new file mode 100644 index 0000000..d56a848 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_negative_net_inflow.png differ diff --git a/test/widgets/goldens/pool_info_modal_net_inflow_tooltip.png b/test/widgets/goldens/pool_info_modal_net_inflow_tooltip.png new file mode 100644 index 0000000..03cd1ac Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_net_inflow_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_net_inflow_tooltip_mobile.png b/test/widgets/goldens/pool_info_modal_net_inflow_tooltip_mobile.png new file mode 100644 index 0000000..0262907 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_net_inflow_tooltip_mobile.png differ diff --git a/test/widgets/goldens/pool_info_modal_neutral_net_inflow.png b/test/widgets/goldens/pool_info_modal_neutral_net_inflow.png new file mode 100644 index 0000000..f5c87a6 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_neutral_net_inflow.png differ diff --git a/test/widgets/goldens/pool_info_modal_swap_volume_tooltip.png b/test/widgets/goldens/pool_info_modal_swap_volume_tooltip.png new file mode 100644 index 0000000..e3a0701 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_swap_volume_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_swap_volume_tooltip_mobile.png b/test/widgets/goldens/pool_info_modal_swap_volume_tooltip_mobile.png new file mode 100644 index 0000000..412e1e4 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_swap_volume_tooltip_mobile.png differ diff --git a/test/widgets/goldens/pool_info_modal_switch_to_24h.png b/test/widgets/goldens/pool_info_modal_switch_to_24h.png new file mode 100644 index 0000000..60b72dc Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_switch_to_24h.png differ diff --git a/test/widgets/goldens/pool_info_modal_switch_to_30d.png b/test/widgets/goldens/pool_info_modal_switch_to_30d.png new file mode 100644 index 0000000..d663099 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_switch_to_30d.png differ diff --git a/test/widgets/goldens/pool_info_modal_switch_to_7d.png b/test/widgets/goldens/pool_info_modal_switch_to_7d.png new file mode 100644 index 0000000..e168a7a Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_switch_to_7d.png differ diff --git a/test/widgets/goldens/pool_info_modal_switch_to_90d.png b/test/widgets/goldens/pool_info_modal_switch_to_90d.png new file mode 100644 index 0000000..e5d7130 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_switch_to_90d.png differ diff --git a/test/widgets/goldens/pool_info_modal_tvl_tooltip.png b/test/widgets/goldens/pool_info_modal_tvl_tooltip.png new file mode 100644 index 0000000..8207d14 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_tvl_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_tvl_tooltip_mobile.png b/test/widgets/goldens/pool_info_modal_tvl_tooltip_mobile.png new file mode 100644 index 0000000..ae07366 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_tvl_tooltip_mobile.png differ diff --git a/test/widgets/goldens/pool_info_modal_yearly_yield_tooltip.png b/test/widgets/goldens/pool_info_modal_yearly_yield_tooltip.png new file mode 100644 index 0000000..9b33962 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_yearly_yield_tooltip.png differ diff --git a/test/widgets/goldens/pool_info_modal_yearly_yield_tooltip_mobile.png b/test/widgets/goldens/pool_info_modal_yearly_yield_tooltip_mobile.png new file mode 100644 index 0000000..9c1d0f3 Binary files /dev/null and b/test/widgets/goldens/pool_info_modal_yearly_yield_tooltip_mobile.png differ diff --git a/test/widgets/goldens/pool_tokens_button_disabled.png b/test/widgets/goldens/pool_tokens_button_disabled.png new file mode 100644 index 0000000..32b3c2c Binary files /dev/null and b/test/widgets/goldens/pool_tokens_button_disabled.png differ diff --git a/test/widgets/goldens/pool_tokens_button_enabled.png b/test/widgets/goldens/pool_tokens_button_enabled.png new file mode 100644 index 0000000..4a06fdf Binary files /dev/null and b/test/widgets/goldens/pool_tokens_button_enabled.png differ diff --git a/test/widgets/goldens/pool_tokens_button_tooltip.png b/test/widgets/goldens/pool_tokens_button_tooltip.png new file mode 100644 index 0000000..128e5fc Binary files /dev/null and b/test/widgets/goldens/pool_tokens_button_tooltip.png differ diff --git a/test/widgets/goldens/token_avatar_empty_logo_url.png b/test/widgets/goldens/token_avatar_empty_logo_url.png index 8fed88d..3deaf0f 100644 Binary files a/test/widgets/goldens/token_avatar_empty_logo_url.png and b/test/widgets/goldens/token_avatar_empty_logo_url.png differ diff --git a/test/widgets/goldens/token_avatar_not_empty_logo_url.png b/test/widgets/goldens/token_avatar_not_empty_logo_url.png index 8d449f9..3deaf0f 100644 Binary files a/test/widgets/goldens/token_avatar_not_empty_logo_url.png and b/test/widgets/goldens/token_avatar_not_empty_logo_url.png differ diff --git a/test/widgets/goldens/token_avatar_size.png b/test/widgets/goldens/token_avatar_size.png index 5265d44..7bf0cab 100644 Binary files a/test/widgets/goldens/token_avatar_size.png and b/test/widgets/goldens/token_avatar_size.png differ diff --git a/test/widgets/goldens/token_group_card_hover_info.png b/test/widgets/goldens/token_group_card_hover_info.png index 12a9dee..afb5861 100644 Binary files a/test/widgets/goldens/token_group_card_hover_info.png and b/test/widgets/goldens/token_group_card_hover_info.png differ diff --git a/test/widgets/goldens/yield_card_blockchain_tooltip_hover.png b/test/widgets/goldens/yield_card_blockchain_tooltip_hover.png index bbd42f3..8c206ff 100644 Binary files a/test/widgets/goldens/yield_card_blockchain_tooltip_hover.png and b/test/widgets/goldens/yield_card_blockchain_tooltip_hover.png differ diff --git a/test/widgets/goldens/yield_card_compacte_tvl.png b/test/widgets/goldens/yield_card_compacte_tvl.png index 54b0466..ea3ecc4 100644 Binary files a/test/widgets/goldens/yield_card_compacte_tvl.png and b/test/widgets/goldens/yield_card_compacte_tvl.png differ diff --git a/test/widgets/goldens/yield_card_dark_mode.png b/test/widgets/goldens/yield_card_dark_mode.png index a473274..f58028a 100644 Binary files a/test/widgets/goldens/yield_card_dark_mode.png and b/test/widgets/goldens/yield_card_dark_mode.png differ diff --git a/test/widgets/goldens/yield_card_day_timeframe.png b/test/widgets/goldens/yield_card_day_timeframe.png index 562fffe..47b9dad 100644 Binary files a/test/widgets/goldens/yield_card_day_timeframe.png and b/test/widgets/goldens/yield_card_day_timeframe.png differ diff --git a/test/widgets/goldens/yield_card_month_timeframe.png b/test/widgets/goldens/yield_card_month_timeframe.png index 3810417..6907908 100644 Binary files a/test/widgets/goldens/yield_card_month_timeframe.png and b/test/widgets/goldens/yield_card_month_timeframe.png differ diff --git a/test/widgets/goldens/yield_card_overflow_protocol_name.png b/test/widgets/goldens/yield_card_overflow_protocol_name.png index 4a1443f..4a0fc89 100644 Binary files a/test/widgets/goldens/yield_card_overflow_protocol_name.png and b/test/widgets/goldens/yield_card_overflow_protocol_name.png differ diff --git a/test/widgets/goldens/yield_card_overflow_token_symbol.png b/test/widgets/goldens/yield_card_overflow_token_symbol.png index d29cd08..00e6c8c 100644 Binary files a/test/widgets/goldens/yield_card_overflow_token_symbol.png and b/test/widgets/goldens/yield_card_overflow_token_symbol.png differ diff --git a/test/widgets/goldens/yield_card_secondary_button.png b/test/widgets/goldens/yield_card_secondary_button.png new file mode 100644 index 0000000..a987fd8 Binary files /dev/null and b/test/widgets/goldens/yield_card_secondary_button.png differ diff --git a/test/widgets/goldens/yield_card_show_yield_timeframe.png b/test/widgets/goldens/yield_card_show_yield_timeframe.png index 22ef99b..f11834f 100644 Binary files a/test/widgets/goldens/yield_card_show_yield_timeframe.png and b/test/widgets/goldens/yield_card_show_yield_timeframe.png differ diff --git a/test/widgets/goldens/yield_card_three_months_timeframe.png b/test/widgets/goldens/yield_card_three_months_timeframe.png index 32db0e2..06e4e8e 100644 Binary files a/test/widgets/goldens/yield_card_three_months_timeframe.png and b/test/widgets/goldens/yield_card_three_months_timeframe.png differ diff --git a/test/widgets/goldens/yield_card_week_timeframe.png b/test/widgets/goldens/yield_card_week_timeframe.png index 13f5abc..752e293 100644 Binary files a/test/widgets/goldens/yield_card_week_timeframe.png and b/test/widgets/goldens/yield_card_week_timeframe.png differ diff --git a/test/widgets/goldens/yield_card_yield_tap_mobile.png b/test/widgets/goldens/yield_card_yield_tap_mobile.png index 744ee2c..d6fbc87 100644 Binary files a/test/widgets/goldens/yield_card_yield_tap_mobile.png and b/test/widgets/goldens/yield_card_yield_tap_mobile.png differ diff --git a/test/widgets/goldens/yield_card_yield_tooltip_hover.png b/test/widgets/goldens/yield_card_yield_tooltip_hover.png index 29d6bda..5dc94a2 100644 Binary files a/test/widgets/goldens/yield_card_yield_tooltip_hover.png and b/test/widgets/goldens/yield_card_yield_tooltip_hover.png differ diff --git a/test/widgets/goldens/zup_header.png b/test/widgets/goldens/zup_header.png index b84b837..697e061 100644 Binary files a/test/widgets/goldens/zup_header.png and b/test/widgets/goldens/zup_header.png differ diff --git a/test/widgets/goldens/zup_header_generic_route_event.png b/test/widgets/goldens/zup_header_generic_route_event.png index b84b837..697e061 100644 Binary files a/test/widgets/goldens/zup_header_generic_route_event.png and b/test/widgets/goldens/zup_header_generic_route_event.png differ diff --git a/test/widgets/goldens/zup_header_mobile.png b/test/widgets/goldens/zup_header_mobile.png index 5d2cf10..a8ef5c6 100644 Binary files a/test/widgets/goldens/zup_header_mobile.png and b/test/widgets/goldens/zup_header_mobile.png differ diff --git a/test/widgets/goldens/zup_header_new_position.png b/test/widgets/goldens/zup_header_new_position.png index 6a65021..2ec6f68 100644 Binary files a/test/widgets/goldens/zup_header_new_position.png and b/test/widgets/goldens/zup_header_new_position.png differ diff --git a/test/widgets/goldens/zup_header_new_position_event.png b/test/widgets/goldens/zup_header_new_position_event.png index 6a65021..2ec6f68 100644 Binary files a/test/widgets/goldens/zup_header_new_position_event.png and b/test/widgets/goldens/zup_header_new_position_event.png differ diff --git a/test/widgets/pool_info_modal_test.dart b/test/widgets/pool_info_modal_test.dart new file mode 100644 index 0000000..403984a --- /dev/null +++ b/test/widgets/pool_info_modal_test.dart @@ -0,0 +1,1114 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:golden_toolkit/golden_toolkit.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; +import 'package:web3kit/core/core.dart'; +import 'package:zup_app/core/dtos/hook_dto.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/dtos/pool_stats_dto.dart'; +import 'package:zup_app/core/dtos/protocol_dto.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; +import 'package:zup_app/core/enums/networks.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; +import 'package:zup_app/core/enums/pool_type.dart'; +import 'package:zup_app/core/extensions/num_extension.dart'; +import 'package:zup_app/core/injections.dart'; +import 'package:zup_app/core/zup_navigator.dart'; +import 'package:zup_app/widgets/pool_info_modal/pool_info_modal.dart'; +import 'package:zup_core/test_utils.dart'; +import 'package:zup_ui_kit/zup_network_image.dart'; + +import '../golden_config.dart'; +import '../mocks.dart'; + +void main() { + late ZupNavigator navigator; + + setUp(() { + registerFallbackValue(LiquidityPoolDto.fixture()); + registerFallbackValue(PoolDataTimeframe.day); + + UrlLauncherPlatform.instance = UrlLauncherPlatformCustomMock(); + + navigator = ZupNavigatorMock(); + + inject.registerFactory(() => navigator); + inject.registerFactory(() => mockZupNetworkImage()); + + when( + () => navigator.navigateToDeposit( + parseWrappedToNative: any(named: "parseWrappedToNative"), + selectedTimeframe: any(named: "selectedTimeframe"), + yieldPool: any(named: "yieldPool"), + ), + ).thenAnswer((_) async {}); + }); + + tearDown(() => inject.reset()); + + Future goldenBuilder({ + LiquidityPoolDto? customPool, + PoolDataTimeframe selectedTimeframe = PoolDataTimeframe.day, + bool isMobile = false, + }) async => await goldenDeviceBuilder( + device: isMobile ? GoldenDevice.mobile : GoldenDevice.pc, + Builder( + builder: (context) { + WidgetsBinding.instance.addPostFrameCallback((_) { + PoolInfoModal.show( + context, + liquidityPool: customPool ?? LiquidityPoolDto.fixture(), + selectedTimeframe: selectedTimeframe, + showAsBottomSheet: isMobile, + ); + }); + + return const SizedBox(); + }, + ), + ); + + zGoldenTest("When clicking the copy icon, it should copy the pool address to the clipboard", (tester) async { + String? clipboardData; + + tester.onSetClipboard((clipboardText) => clipboardData = clipboardText); + + const poolAddress = "xabasMaPol"; + final pool = LiquidityPoolDto.fixture().copyWith(poolAddress: poolAddress); + await tester.pumpDeviceBuilder(await goldenBuilder(customPool: pool), wrapper: GoldenConfig.localizationsWrapper()); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("pool-info-modal-copy-pool-address"))); + await tester.pumpAndSettle(const Duration(seconds: 5)); + + expect(clipboardData, poolAddress); + }); + + zGoldenTest( + """When hovering the copy pool address button, it should show a tooltip + explaning that the address will be copied on click""", + goldenFileName: "pool_info_modal_copy_pool_address_tooltip", + (tester) async { + await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(const Key("pool-info-modal-copy-pool-address"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + """When pressing the copy pool address button, while hovering + it should change the tooltip to "Copied!" and show a checkmark icon""", + (tester) async { + await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(const Key("pool-info-modal-copy-pool-address"))); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("pool-info-modal-copy-pool-address"))); + await tester.pumpAndSettle(); + + await screenMatchesGolden(tester, "pool_info_modal_copy_pool_address_tooltip_copied"); + await tester.pumpAndSettle(const Duration(seconds: 10)); + }, + ); + + zGoldenTest( + """When clicking the add liquidity button, it should pop the modal, and navigate to deposit page + passing the pool object and the selected timeframe""", + goldenFileName: "pool_info_modal_add_liquidity_pop", + (tester) async { + const expectedTimeframe = PoolDataTimeframe.week; + final expectedPool = LiquidityPoolDto.fixture().copyWith(poolAddress: "some random address"); + + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: expectedPool, selectedTimeframe: expectedTimeframe), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("pool-info-modal-add-liquidity"))); + await tester.pumpAndSettle(); + + verify( + () => navigator.navigateToDeposit( + parseWrappedToNative: any(named: "parseWrappedToNative"), + selectedTimeframe: expectedTimeframe, + yieldPool: expectedPool, + ), + ).called(1); + }, + ); + + zGoldenTest( + """When clicking the add liquidity button with a pool that has the token 0 as native, + it should pass to parseWrappedToNative true when navigating to the deposit page""", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder( + customPool: LiquidityPoolDto.fixture().copyWith( + token0: const SingleChainTokenDto(address: EthereumConstants.zeroAddress), + token1: const SingleChainTokenDto(address: "0x123"), + ), + ), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("pool-info-modal-add-liquidity"))); + await tester.pumpAndSettle(); + + verify( + () => navigator.navigateToDeposit( + parseWrappedToNative: true, + selectedTimeframe: any(named: "selectedTimeframe"), + yieldPool: any(named: "yieldPool"), + ), + ).called(1); + }, + ); + + zGoldenTest( + """When clicking the add liquidity button with a pool that has the token 1 as native, + it should pass to parseWrappedToNative true when navigating to the deposit page""", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder( + customPool: LiquidityPoolDto.fixture().copyWith( + token0: const SingleChainTokenDto(address: "0x123"), + token1: const SingleChainTokenDto(address: EthereumConstants.zeroAddress), + ), + ), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("pool-info-modal-add-liquidity"))); + await tester.pumpAndSettle(); + + verify( + () => navigator.navigateToDeposit( + parseWrappedToNative: true, + selectedTimeframe: any(named: "selectedTimeframe"), + yieldPool: any(named: "yieldPool"), + ), + ).called(1); + }, + ); + + zGoldenTest( + """When clicking the add liquidity button with a pool that does not have the + token 0 or 1 as native, it should pass to parseWrappedToNative false when + navigating to the deposit page""", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder( + customPool: LiquidityPoolDto.fixture().copyWith( + token0: const SingleChainTokenDto(address: "0x123"), + token1: const SingleChainTokenDto(address: "0x456"), + ), + ), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("pool-info-modal-add-liquidity"))); + await tester.pumpAndSettle(); + + verify( + () => navigator.navigateToDeposit( + parseWrappedToNative: false, + selectedTimeframe: any(named: "selectedTimeframe"), + yieldPool: any(named: "yieldPool"), + ), + ).called(1); + }, + ); + + group("Pool Stats Page Tests", () { + final poolWithTimeframeStats = LiquidityPoolDto.fixture().copyWith( + totalValueLockedUSD: 787878, + total24hStats: const PoolTotalStatsDTO( + totalFees: 242424, + totalNetInflow: 240240240, + totalVolume: 240024002400, + yearlyYield: 240002400024000, + ), + total7dStats: const PoolTotalStatsDTO( + totalFees: 777, + totalNetInflow: 7777, + totalVolume: 77777, + yearlyYield: 777777, + ), + total30dStats: const PoolTotalStatsDTO( + totalFees: 303030, + totalNetInflow: 300300300, + totalVolume: 300030003000, + yearlyYield: 3000030003000, + ), + total90dStats: const PoolTotalStatsDTO( + totalFees: 909090, + totalNetInflow: 900900900, + totalVolume: 900090009000, + yearlyYield: 9000090009000, + ), + ); + + zGoldenTest( + """When passing the 24h timeframe, it should show the 24h stats + when opening the modal""", + goldenFileName: "pool_info_modal_24h_initial", + (tester) async { + const expectedTimeframe = PoolDataTimeframe.day; + + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats, selectedTimeframe: expectedTimeframe), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + """When passing the 7d timeframe, it should show the 7d stats + when opening the modal""", + goldenFileName: "pool_info_modal_7d_initial", + (tester) async { + const expectedTimeframe = PoolDataTimeframe.week; + + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats, selectedTimeframe: expectedTimeframe), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + """When passing the 30d timeframe, it should show the 30d stats + when opening the modal""", + goldenFileName: "pool_info_modal_30d_initial", + (tester) async { + const expectedTimeframe = PoolDataTimeframe.month; + + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats, selectedTimeframe: expectedTimeframe), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + """When passing the 90d timeframe, it should show the 90d stats + when opening the modal""", + goldenFileName: "pool_info_modal_90d_initial", + (tester) async { + const expectedTimeframe = PoolDataTimeframe.threeMonth; + + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats, selectedTimeframe: expectedTimeframe), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When starting with 24h timeframe, but the user clicks on the 7d timeframe, it should show the 7d stats", + goldenFileName: "pool_info_modal_switch_to_7d", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats, selectedTimeframe: PoolDataTimeframe.day), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(Key("${PoolDataTimeframe.week.name}-timeframe-button"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When starting with 24h timeframe, but the user clicks on the 30d timeframe, it should show the 30d stats", + goldenFileName: "pool_info_modal_switch_to_30d", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats, selectedTimeframe: PoolDataTimeframe.day), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(Key("${PoolDataTimeframe.month.name}-timeframe-button"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When starting with 24h timeframe, but the user clicks on the 90d timeframe, it should show the 90d stats", + goldenFileName: "pool_info_modal_switch_to_90d", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats, selectedTimeframe: PoolDataTimeframe.day), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(Key("${PoolDataTimeframe.threeMonth.name}-timeframe-button"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When starting with 7d timeframe, but the user clicks on the 24h timeframe, it should show the 24h stats", + goldenFileName: "pool_info_modal_switch_to_24h", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats, selectedTimeframe: PoolDataTimeframe.week), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(Key("${PoolDataTimeframe.day.name}-timeframe-button"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When hovering the tvl info icon, it should show a tooltip explaining the TVL and Timeframe", + goldenFileName: "pool_info_modal_tvl_tooltip", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(const Key("TVL-tooltip"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When the device size is mobile, and the user clicks the tvl value, it should show a tooltip explaining the TVL and Timeframe", + goldenFileName: "pool_info_modal_tvl_tooltip_mobile", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats, isMobile: true), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.text(poolWithTimeframeStats.totalValueLockedUSD.formatCompactCurrency().toString())); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When hovering the swap volume info icon, it should show a tooltip explaining the Swap Volume and Timeframe", + goldenFileName: "pool_info_modal_swap_volume_tooltip", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(const Key("24h Swap Volume-tooltip"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When the device size is mobile, and the user clicks the swap volume value, it should show a tooltip explaining it", + goldenFileName: "pool_info_modal_swap_volume_tooltip_mobile", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats, isMobile: true), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap( + find.text(poolWithTimeframeStats.total24hStats!.totalVolume.formatCompactCurrency().toString()), + ); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When hovering the fees info icon, it should show a tooltip explaining the Fees and Timeframe", + goldenFileName: "pool_info_modal_fees_tooltip", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(const Key("24h Fees-tooltip"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When the device size is mobile, and the user clicks the fees value, it should show a tooltip explaining it", + goldenFileName: "pool_info_modal_fees_tooltip_mobile", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats, isMobile: true), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.text(poolWithTimeframeStats.total24hStats!.totalFees.formatCompactCurrency().toString())); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When hovering the net inflow info icon, it should show a tooltip explaining it", + goldenFileName: "pool_info_modal_net_inflow_tooltip", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(const Key("24h Net Inflow-tooltip"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When the device size is mobile, and the user clicks the net inflow value, it should show a tooltip explaining it", + goldenFileName: "pool_info_modal_net_inflow_tooltip_mobile", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats, isMobile: true), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap( + find.text(poolWithTimeframeStats.total24hStats!.totalNetInflow.formatCompactCurrency().toString()), + ); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When hovering the yearly yield info icon, it should show a tooltip explaining it", + goldenFileName: "pool_info_modal_yearly_yield_tooltip", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(const Key("24h Yearly Yield-tooltip"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When the device size is mobile, and the user clicks the yearly yield value, it should show a tooltip explaining it", + goldenFileName: "pool_info_modal_yearly_yield_tooltip_mobile", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithTimeframeStats, isMobile: true), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + await tester.pumpAndSettle(); + + await tester.drag( + find.text(poolWithTimeframeStats.total24hStats!.totalFees.formatCompactCurrency().toString()), + const Offset(0, -500), + ); + + await tester.pumpAndSettle(); + + await tester.tap(find.text(poolWithTimeframeStats.total24hStats!.yearlyYield.formatRoundingPercent.toString())); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When the net inflow value is negative, it should be red", + goldenFileName: "pool_info_modal_negative_net_inflow", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder( + customPool: poolWithTimeframeStats.copyWith( + total24hStats: poolWithTimeframeStats.total24hStats!.copyWith(totalNetInflow: -12189), + ), + ), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When the net inflow value is zero, it should be gray", + goldenFileName: "pool_info_modal_neutral_net_inflow", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder( + customPool: poolWithTimeframeStats.copyWith( + total24hStats: poolWithTimeframeStats.total24hStats!.copyWith(totalNetInflow: 0), + ), + ), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + await tester.pumpAndSettle(); + }, + ); + }); + + group("About pool page", () { + final poolWithAbout = LiquidityPoolDto.fixture().copyWith( + currentFeeTier: 1200, + chainId: AppNetworks.base.chainId, + poolType: PoolType.v3, + ); + + zGoldenTest( + "When clicking the about tab bar, it should switch to the about page", + goldenFileName: "pool_info_modal_about_tab_switch", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When hovering the info icon in the fee, it should show a tooltip explaining the fee tier", + goldenFileName: "pool_info_modal_about_tab_fee_tier_tooltip", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(const Key("fee-tooltip"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When clicking the fee tier value, and the device size is mobile, it should show a tooltip explaining the fee tier", + goldenFileName: "pool_info_modal_about_tab_fee_tier_tooltip_mobile", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout, isMobile: true), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.tap(find.text(poolWithAbout.currentFeeTierFormatted)); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + """When the pool hook is dynamic fee, it should show dynamic in the fee tier field + and in the tooltip""", + goldenFileName: "pool_info_modal_dynamic_fee", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout.copyWith(hook: HookDto.fixture().copyWith(isDynamicFee: true))), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(const Key("fee-tooltip"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + """When hovering the info icon in the pool type, and the pool type is v3, + it should show a tooltip explaining the v3 pool type""", + goldenFileName: "pool_info_modal_about_tab_v3_pool_type_tooltip", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout.copyWith(poolType: PoolType.v3)), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(const Key("pool-type-tooltip"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + """When hovering the info icon in the pool type, and the pool type is v4, + it should show a tooltip explaining the v4 pool type""", + goldenFileName: "pool_info_modal_about_tab_v4_pool_type_tooltip", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout.copyWith(poolType: PoolType.v4)), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(const Key("pool-type-tooltip"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When clicking the pool type value, and the device size is mobile, it should show a tooltip explaining the pool type", + goldenFileName: "pool_info_modal_about_tab_pool_type_tooltip_mobile", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout.copyWith(poolType: PoolType.v3), isMobile: true), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.tap(find.text("V3 Pool")); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + """When the pool is v4, and hover the info icon in the hooks field, + it should show a tooltip explaining hooks""", + goldenFileName: "pool_info_modal_about_tab_v4_hooks_tooltip", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout.copyWith(poolType: PoolType.v4)), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(const Key("hooks-tooltip"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When clicking the hooks value, and the device size is mobile, it should show a tooltip explaining hooks", + goldenFileName: "pool_info_modal_about_tab_hooks_tooltip_mobile", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout.copyWith(poolType: PoolType.v4), isMobile: true), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.tap(find.text("Hooks")); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When the pool is v4, and the hooks are not null, it should show the hooks address shortened", + goldenFileName: "pool_info_modal_about_tab_v4_hooks_address", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder( + customPool: poolWithAbout.copyWith( + poolType: PoolType.v4, + hook: const HookDto(address: "0x1234567891011", isDynamicFee: false), + ), + ), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + """When the pool is v4, the hooks are not null, and the user hover the copy button, + it should show a tooltip explaining the copy button""", + goldenFileName: "pool_info_modal_about_tab_v4_hooks_copy_tooltip", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder( + customPool: poolWithAbout.copyWith( + poolType: PoolType.v4, + hook: const HookDto(address: "0x1234567891011", isDynamicFee: false), + ), + ), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(const Key("copy-hook-button"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + """When the pool is v4, the hooks are not null, and the user hover the copy button, + then click, it should show a tooltip that the address was copied""", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder( + customPool: poolWithAbout.copyWith( + poolType: PoolType.v4, + hook: const HookDto(address: "0x1234567891011", isDynamicFee: false), + ), + ), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(const Key("copy-hook-button"))); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("copy-hook-button"))); + await tester.pumpAndSettle(); + + await screenMatchesGolden(tester, "pool_info_modal_about_tab_v4_hooks_copied_tooltip"); + await tester.pumpAndSettle(const Duration(seconds: 10)); + }, + ); + + zGoldenTest( + """When the pool is v4, the hooks are not null, and the user click the copy + hook address button, it should copy the hook address to clipboard""", + (tester) async { + String? copiedAdddress; + const hooksAddress = "0x ma Hook aaaddrresss"; + + tester.onSetClipboard((clipboard) => copiedAdddress = clipboard); + + await tester.pumpDeviceBuilder( + await goldenBuilder( + customPool: poolWithAbout.copyWith( + poolType: PoolType.v4, + hook: const HookDto(address: hooksAddress, isDynamicFee: false), + ), + ), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("copy-hook-button"))); + await tester.pumpAndSettle(const Duration(seconds: 5)); + + expect(copiedAdddress, hooksAddress); + }, + ); + + zGoldenTest( + """When the token 0 is native, the button to navigate to the token address + and the copy button should be hidden, and it should only show the symbol / image""", + goldenFileName: "pool_info_modal_about_tab_token_0_native", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder( + customPool: poolWithAbout.copyWith( + token0: SingleChainTokenDto.fixture().copyWith(address: EthereumConstants.zeroAddress, symbol: "ETH"), + ), + ), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + """When the token 0 is not native, and clicking the token button, + it should launch the network explorer at the token address""", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(Key("${poolWithAbout.token0.address}-button"))); + await tester.pumpAndSettle(); + + expect( + UrlLauncherPlatformCustomMock.lastLaunchedUrl, + "${poolWithAbout.network.chainInfo.blockExplorerUrls?.first}/address/${poolWithAbout.token0.address}", + ); + }, + ); + + zGoldenTest( + """When the token 0 is not native, and hovering the copy token address button + it should show a tooltip explaining the copy button""", + goldenFileName: "pool_info_modal_about_tab_token_0_copy_tooltip", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(Key("${poolWithAbout.token0.address}-copy-button"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + """When the token 1 is not native, and hovering the copy token address button + it should show a tooltip explaining the copy button""", + goldenFileName: "pool_info_modal_about_tab_token_1_copy_tooltip", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(Key("${poolWithAbout.token1.address}-copy-button"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + """When the token 0 is not native, and hovering the copy token address button + then clicking it, it should show a tooltip saying the address was copied""", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(Key("${poolWithAbout.token0.address}-copy-button"))); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(Key("${poolWithAbout.token0.address}-copy-button"))); + await tester.pumpAndSettle(); + + await screenMatchesGolden(tester, "pool_info_modal_about_tab_token_0_copied_tooltip"); + await tester.pumpAndSettle(const Duration(seconds: 10)); + }, + ); + + zGoldenTest( + """When the token 1 is not native, and hovering the copy token address button + then clicking it, it should show a tooltip saying the address was copied""", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.hover(find.byKey(Key("${poolWithAbout.token1.address}-copy-button"))); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(Key("${poolWithAbout.token1.address}-copy-button"))); + await tester.pumpAndSettle(); + + await screenMatchesGolden(tester, "pool_info_modal_about_tab_token_1_copied_tooltip"); + await tester.pumpAndSettle(const Duration(seconds: 10)); + }, + ); + + zGoldenTest("When clicking the token 0 copy button, it should copy the token0 address to clipboard", ( + tester, + ) async { + String? clipboardAddress; + + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + tester.onSetClipboard((clipboardText) => clipboardAddress = clipboardText); + + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(Key("${poolWithAbout.token0.address}-copy-button"))); + await tester.pumpAndSettle(const Duration(seconds: 5)); + + expect(clipboardAddress, poolWithAbout.token0.address); + }); + + zGoldenTest("When clicking the token 1 copy button, it should copy the token1 address to clipboard", ( + tester, + ) async { + String? clipboardAddress; + + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + tester.onSetClipboard((clipboardText) => clipboardAddress = clipboardText); + + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(Key("${poolWithAbout.token1.address}-copy-button"))); + await tester.pumpAndSettle(const Duration(seconds: 5)); + + expect(clipboardAddress, poolWithAbout.token1.address); + }); + + zGoldenTest( + """When the token 1 is not native, and clicking the token button, + it should launch the network explorer at the token address""", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout), + wrapper: GoldenConfig.localizationsWrapper(), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(Key("${poolWithAbout.token1.address}-button"))); + await tester.pumpAndSettle(); + + expect( + UrlLauncherPlatformCustomMock.lastLaunchedUrl, + "${poolWithAbout.network.chainInfo.blockExplorerUrls?.first}/address/${poolWithAbout.token1.address}", + ); + }, + ); + + zGoldenTest( + """When the token 1 is native, the button to navigate to the token address + and the copy button should be hidden, and it should only show the symbol / image""", + goldenFileName: "pool_info_modal_about_tab_token_1_native", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder( + customPool: poolWithAbout.copyWith( + token1: SingleChainTokenDto.fixture().copyWith(address: EthereumConstants.zeroAddress, symbol: "ETH"), + ), + ), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest("When clicking the protocol button, it should launch the protocol website", (tester) async { + const protocolWebsite = "maProtocolWebsite"; + + await tester.pumpDeviceBuilder( + await goldenBuilder( + customPool: poolWithAbout.copyWith(protocol: ProtocolDto.fixture().copyWith(url: protocolWebsite)), + ), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("protocol-button"))); + await tester.pumpAndSettle(); + + expect(UrlLauncherPlatformCustomMock.lastLaunchedUrl, protocolWebsite); + }); + + zGoldenTest("When clicking the network button, it should launch the network website", (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: poolWithAbout), + wrapper: GoldenConfig.localizationsWrapper(), + ); + + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("about-tab"))); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("network-button"))); + await tester.pumpAndSettle(); + + expect(UrlLauncherPlatformCustomMock.lastLaunchedUrl, poolWithAbout.network.websiteUrl); + }); + }); +} diff --git a/test/widgets/pool_tokens_button_test.dart b/test/widgets/pool_tokens_button_test.dart new file mode 100644 index 0000000..2e53bdf --- /dev/null +++ b/test/widgets/pool_tokens_button_test.dart @@ -0,0 +1,91 @@ +import 'package:flutter/src/widgets/basic.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:golden_toolkit/golden_toolkit.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/enums/networks.dart'; +import 'package:zup_app/core/injections.dart'; +import 'package:zup_app/widgets/pool_tokens_button.dart'; +import 'package:zup_core/test_utils.dart'; +import 'package:zup_ui_kit/zup_network_image.dart'; + +import '../golden_config.dart'; +import '../mocks.dart'; + +void main() { + setUp(() { + UrlLauncherPlatform.instance = UrlLauncherPlatformCustomMock(); + inject.registerFactory(() => mockZupNetworkImage()); + }); + + tearDown(() => inject.reset()); + + Future goldenBuilder({LiquidityPoolDto? customPool}) async { + return await goldenDeviceBuilder( + Center(child: PoolTokensButton(liquidityPool: customPool ?? LiquidityPoolDto.fixture())), + device: GoldenDevice.square, + ); + } + + zGoldenTest( + "When the dexscrenner URL is null at the pool network, the button should be disabled", + goldenFileName: "pool_tokens_button_disabled", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: LiquidityPoolDto.fixture().copyWith(chainId: AppNetworks.sepolia.chainId)), + ); + }, + ); + + zGoldenTest( + "When the dexscrenner URL is not null at the pool network, the button should be in enabled state", + goldenFileName: "pool_tokens_button_enabled", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: LiquidityPoolDto.fixture().copyWith(chainId: AppNetworks.mainnet.chainId)), + ); + }, + ); + + zGoldenTest( + """When the button is enabled, and the user hovers the button, it should show a tooltip with a message + about launching on dex screener""", + goldenFileName: "pool_tokens_button_tooltip", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(customPool: LiquidityPoolDto.fixture().copyWith(chainId: AppNetworks.mainnet.chainId)), + ); + + await tester.hover(find.byType(PoolTokensButton)); + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + """When the button is enabled, and is clicked, it should launch on dex screener at + the current network and with the correct pool address""", + (tester) async { + const network = AppNetworks.unichain; + final pool = LiquidityPoolDto.fixture().copyWith(chainId: network.chainId); + + await tester.pumpDeviceBuilder(await goldenBuilder(customPool: pool)); + + await tester.tap(find.byType(PoolTokensButton)); + await tester.pumpAndSettle(); + + expect(UrlLauncherPlatformCustomMock.lastLaunchedUrl, "${pool.network.dexscreenerUrl}/${pool.poolAddress}"); + }, + ); + + zGoldenTest("""When the button is disabled, and is clicked, it should not launch anything""", (tester) async { + const network = AppNetworks.sepolia; + final pool = LiquidityPoolDto.fixture().copyWith(chainId: network.chainId); + + await tester.pumpDeviceBuilder(await goldenBuilder(customPool: pool)); + + await tester.tap(find.byType(PoolTokensButton)); + await tester.pumpAndSettle(); + + expect(UrlLauncherPlatformCustomMock.lastLaunchedUrl, null); + }); +} diff --git a/test/widgets/token_avatar_test.dart b/test/widgets/token_avatar_test.dart index dd81da3..35f7220 100644 --- a/test/widgets/token_avatar_test.dart +++ b/test/widgets/token_avatar_test.dart @@ -2,51 +2,56 @@ import 'package:flutter/src/widgets/basic.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:golden_toolkit/golden_toolkit.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/injections.dart'; -import 'package:zup_app/widgets/token_avatar.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; +import 'package:zup_ui_kit/zup_network_image.dart'; +import 'package:zup_ui_kit/zup_remote_avatar.dart'; import '../golden_config.dart'; import '../mocks.dart'; void main() { setUp(() { - inject.registerFactory(() => mockZupCachedImage()); + inject.registerFactory(() => mockZupNetworkImage()); }); tearDown(() => inject.reset()); - Future goldenBuilder({TokenDto? token, double size = 30}) => goldenDeviceBuilder( - Center( - child: TokenAvatar( - asset: token ?? const TokenDto(logoUrl: 'https://www.google.com.br', name: 'Zup'), size: size), - ), - device: GoldenDevice.square, - ); + Future goldenBuilder({MultiChainTokenDto? token, double size = 30}) => goldenDeviceBuilder( + Center( + child: ZupRemoteAvatar(avatarUrl: 'https://www.google.com.br', errorPlaceholder: 'Zup', size: size), + ), + device: GoldenDevice.square, + ); zGoldenTest( "When the logoUrl from the dto is empty, it should create an avatar with the initial letter of the token name", goldenFileName: "token_avatar_empty_logo_url", (tester) async { - await tester - .pumpDeviceBuilder(await goldenBuilder(token: TokenDto.fixture().copyWith(logoUrl: '', name: "ZUP TOKEN"))); + await tester.pumpDeviceBuilder( + await goldenBuilder( + token: MultiChainTokenDto.fixture().copyWith(logoUrl: '', name: "ZUP TOKEN"), + ), + ); }, ); zGoldenTest( - "When the logoUrl from the dto is not empty, it should use the url to get the image with $ZupCachedImage", + "When the logoUrl from the dto is not empty, it should use the url to get the image with $ZupNetworkImage", goldenFileName: "token_avatar_not_empty_logo_url", (tester) async { const url = "some_url"; - await tester.pumpDeviceBuilder(await goldenBuilder(token: TokenDto.fixture().copyWith(logoUrl: url))); + await tester.pumpDeviceBuilder(await goldenBuilder(token: MultiChainTokenDto.fixture().copyWith(logoUrl: url))); await tester.pumpAndSettle(); }, ); - zGoldenTest("When passing a size to the widget, it should be applied", goldenFileName: "token_avatar_size", - (tester) async { - await tester.pumpDeviceBuilder(await goldenBuilder(token: TokenDto.fixture().copyWith(logoUrl: ''), size: 200)); + zGoldenTest("When passing a size to the widget, it should be applied", goldenFileName: "token_avatar_size", ( + tester, + ) async { + await tester.pumpDeviceBuilder( + await goldenBuilder(token: MultiChainTokenDto.fixture().copyWith(logoUrl: ''), size: 200), + ); }); } diff --git a/test/widgets/token_card_test.dart b/test/widgets/token_card_test.dart index 437f90d..a3e8472 100644 --- a/test/widgets/token_card_test.dart +++ b/test/widgets/token_card_test.dart @@ -1,34 +1,28 @@ import 'package:flutter/src/widgets/basic.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:golden_toolkit/golden_toolkit.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/widgets/token_card.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; -import 'package:zup_core/zup_core.dart'; +import 'package:zup_core/test_utils.dart'; +import 'package:zup_ui_kit/zup_network_image.dart'; import '../golden_config.dart'; import '../mocks.dart'; void main() { setUp(() { - inject.registerFactory(() => mockZupCachedImage()); + inject.registerFactory(() => mockZupNetworkImage()); }); tearDown(() => inject.reset()); - Future goldenBuilder({ - TokenDto? asset, - Function()? onClick, - }) async => + Future goldenBuilder({MultiChainTokenDto? asset, Function()? onClick}) async => await goldenDeviceBuilder( Center( child: SizedBox( width: 400, - child: TokenCard( - asset: asset ?? TokenDto.fixture(), - onClick: onClick ?? () {}, - ), + child: TokenCard(asset: asset ?? MultiChainTokenDto.fixture(), onClick: onClick ?? () {}), ), ), ); @@ -37,8 +31,9 @@ void main() { await tester.pumpDeviceBuilder(await goldenBuilder()); }); - zGoldenTest("When hovering the card, it should show the hover state", goldenFileName: "token_card_hover", - (tester) async { + zGoldenTest("When hovering the card, it should show the hover state", goldenFileName: "token_card_hover", ( + tester, + ) async { await tester.pumpDeviceBuilder(await goldenBuilder()); await tester.pumpAndSettle(); diff --git a/test/widgets/token_group_card_test.dart b/test/widgets/token_group_card_test.dart index 481cbac..aad1752 100644 --- a/test/widgets/token_group_card_test.dart +++ b/test/widgets/token_group_card_test.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:golden_toolkit/golden_toolkit.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/dtos/token_group_dto.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/widgets/token_group_card.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; -import 'package:zup_core/zup_core.dart'; +import 'package:zup_core/test_utils.dart'; +import 'package:zup_ui_kit/zup_network_image.dart'; import 'package:zup_ui_kit/zup_tooltip.dart'; import '../golden_config.dart'; @@ -14,7 +14,7 @@ import '../mocks.dart'; void main() { setUp(() { - inject.registerFactory(() => mockZupCachedImage()); + inject.registerFactory(() => mockZupNetworkImage()); }); tearDown(() => inject.reset()); @@ -52,7 +52,7 @@ void main() { goldenFileName: "token_group_card_hover_info", (tester) async { final group = TokenGroupDto.fixture().copyWith( - tokens: List.generate(20, (index) => TokenDto.fixture().copyWith(symbol: "Token$index")), + tokens: List.generate(20, (index) => MultiChainTokenDto.fixture().copyWith(symbol: "Token$index")), ); await tester.pumpDeviceBuilder(await goldenBuilder(group: group)); diff --git a/test/widgets/token_selector_button/goldens/token_selector_button_click.png b/test/widgets/token_selector_button/goldens/token_selector_button_click.png index c7f1b75..0a96e31 100644 Binary files a/test/widgets/token_selector_button/goldens/token_selector_button_click.png and b/test/widgets/token_selector_button/goldens/token_selector_button_click.png differ diff --git a/test/widgets/token_selector_button/goldens/token_selector_button_click_mobile.png b/test/widgets/token_selector_button/goldens/token_selector_button_click_mobile.png index 308c8bd..662242d 100644 Binary files a/test/widgets/token_selector_button/goldens/token_selector_button_click_mobile.png and b/test/widgets/token_selector_button/goldens/token_selector_button_click_mobile.png differ diff --git a/test/widgets/token_selector_button/goldens/token_selector_button_selection_token_group.png b/test/widgets/token_selector_button/goldens/token_selector_button_selection_token_group.png index 09f9623..faf8768 100644 Binary files a/test/widgets/token_selector_button/goldens/token_selector_button_selection_token_group.png and b/test/widgets/token_selector_button/goldens/token_selector_button_selection_token_group.png differ diff --git a/test/widgets/token_selector_button/token_selector_button_controller_test.dart b/test/widgets/token_selector_button/token_selector_button_controller_test.dart index e30d3c9..13679cc 100644 --- a/test/widgets/token_selector_button/token_selector_button_controller_test.dart +++ b/test/widgets/token_selector_button/token_selector_button_controller_test.dart @@ -1,5 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/dtos/token_group_dto.dart'; import 'package:zup_app/widgets/token_selector_button/token_selector_button_controller.dart'; @@ -11,7 +11,7 @@ void main() { }); test("When changing the selected token by calling the function, it should set the variable", () { - final newSelectedToken = TokenDto.fixture(); + final newSelectedToken = MultiChainTokenDto.fixture(); /// make sure that the already selected token is not the new one expect(sut.selectedToken, null); @@ -22,7 +22,7 @@ void main() { }); test("When changing the selected token by calling the function, it should emit a event", () { - final newSelectedToken = TokenDto.fixture(); + final newSelectedToken = MultiChainTokenDto.fixture(); expectLater(sut.selectedTokenStream, emits(newSelectedToken)); @@ -30,7 +30,7 @@ void main() { }); test("When changing the selected token to null, it should emit a null event", () { - sut.changeToken(TokenDto.fixture()); + sut.changeToken(MultiChainTokenDto.fixture()); expectLater(sut.selectedTokenStream, emits(null)); sut.changeToken(null); @@ -38,7 +38,7 @@ void main() { test("When there is a selected group, and a call to 'changeToken' is made, it should remove the selected group", () { sut.changeTokenGroup(TokenGroupDto.fixture()); - sut.changeToken(TokenDto.fixture()); + sut.changeToken(MultiChainTokenDto.fixture()); expect(sut.selectedTokenGroup, null); }); @@ -47,18 +47,18 @@ void main() { sut.changeTokenGroup(TokenGroupDto.fixture()); expectLater(sut.selectedTokenGroupStream, emits(null)); - sut.changeToken(TokenDto.fixture()); + sut.changeToken(MultiChainTokenDto.fixture()); }); test("When calling 'changeTokenGroup' with a previous selected token, it should remove the selected token", () { - sut.changeToken(TokenDto.fixture()); + sut.changeToken(MultiChainTokenDto.fixture()); sut.changeTokenGroup(TokenGroupDto.fixture()); expect(sut.selectedToken, null); }); test("When calling 'changeTokenGroup' with a previous selected token, it should emit null selected token", () { - sut.changeToken(TokenDto.fixture()); + sut.changeToken(MultiChainTokenDto.fixture()); expectLater(sut.selectedTokenStream, emits(null)); sut.changeTokenGroup(TokenGroupDto.fixture()); diff --git a/test/widgets/token_selector_button/token_selector_button_test.dart b/test/widgets/token_selector_button/token_selector_button_test.dart index 2c3a9b7..8e16f63 100644 --- a/test/widgets/token_selector_button/token_selector_button_test.dart +++ b/test/widgets/token_selector_button/token_selector_button_test.dart @@ -14,8 +14,8 @@ import 'package:zup_app/widgets/token_group_card.dart'; import 'package:zup_app/widgets/token_selector_button/token_selector_button.dart'; import 'package:zup_app/widgets/token_selector_button/token_selector_button_controller.dart'; import 'package:zup_app/widgets/token_selector_modal/token_selector_modal_cubit.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; -import 'package:zup_core/zup_core.dart'; +import 'package:zup_core/test_utils.dart'; +import 'package:zup_ui_kit/zup_network_image.dart'; import '../../golden_config.dart'; import '../../mocks.dart'; @@ -32,7 +32,7 @@ void main() { registerFallbackValue(AppNetworks.sepolia); - inject.registerFactory(() => mockZupCachedImage()); + inject.registerFactory(() => mockZupNetworkImage()); inject.registerLazySingleton( () => TokenSelectorModalCubit(tokensRepository, appCubit, wallet), ); diff --git a/test/widgets/token_selector_modal/goldens/token_selector_modal_all_networks.png b/test/widgets/token_selector_modal/goldens/token_selector_modal_all_networks.png index f7507a9..8d01a3d 100644 Binary files a/test/widgets/token_selector_modal/goldens/token_selector_modal_all_networks.png and b/test/widgets/token_selector_modal/goldens/token_selector_modal_all_networks.png differ diff --git a/test/widgets/token_selector_modal/goldens/token_selector_modal_error_state.png b/test/widgets/token_selector_modal/goldens/token_selector_modal_error_state.png index 44b130e..690812a 100644 Binary files a/test/widgets/token_selector_modal/goldens/token_selector_modal_error_state.png and b/test/widgets/token_selector_modal/goldens/token_selector_modal_error_state.png differ diff --git a/test/widgets/token_selector_modal/goldens/token_selector_modal_loading.png b/test/widgets/token_selector_modal/goldens/token_selector_modal_loading.png index 7ddb153..5a1b0b4 100644 Binary files a/test/widgets/token_selector_modal/goldens/token_selector_modal_loading.png and b/test/widgets/token_selector_modal/goldens/token_selector_modal_loading.png differ diff --git a/test/widgets/token_selector_modal/goldens/token_selector_modal_search_error_state.png b/test/widgets/token_selector_modal/goldens/token_selector_modal_search_error_state.png index 898248b..c9c2e72 100644 Binary files a/test/widgets/token_selector_modal/goldens/token_selector_modal_search_error_state.png and b/test/widgets/token_selector_modal/goldens/token_selector_modal_search_error_state.png differ diff --git a/test/widgets/token_selector_modal/goldens/token_selector_modal_search_loading.png b/test/widgets/token_selector_modal/goldens/token_selector_modal_search_loading.png index 0e71de2..755e7ba 100644 Binary files a/test/widgets/token_selector_modal/goldens/token_selector_modal_search_loading.png and b/test/widgets/token_selector_modal/goldens/token_selector_modal_search_loading.png differ diff --git a/test/widgets/token_selector_modal/goldens/token_selector_modal_search_not_found.png b/test/widgets/token_selector_modal/goldens/token_selector_modal_search_not_found.png index 93ff27e..a5f0620 100644 Binary files a/test/widgets/token_selector_modal/goldens/token_selector_modal_search_not_found.png and b/test/widgets/token_selector_modal/goldens/token_selector_modal_search_not_found.png differ diff --git a/test/widgets/token_selector_modal/goldens/token_selector_modal_search_success.png b/test/widgets/token_selector_modal/goldens/token_selector_modal_search_success.png index 50cc958..c82913d 100644 Binary files a/test/widgets/token_selector_modal/goldens/token_selector_modal_search_success.png and b/test/widgets/token_selector_modal/goldens/token_selector_modal_search_success.png differ diff --git a/test/widgets/token_selector_modal/goldens/token_selector_modal_success.png b/test/widgets/token_selector_modal/goldens/token_selector_modal_success.png index c47be4b..ba1885d 100644 Binary files a/test/widgets/token_selector_modal/goldens/token_selector_modal_success.png and b/test/widgets/token_selector_modal/goldens/token_selector_modal_success.png differ diff --git a/test/widgets/token_selector_modal/goldens/token_selector_modal_token_groups_tooltip.png b/test/widgets/token_selector_modal/goldens/token_selector_modal_token_groups_tooltip.png index 58e26d2..06f312c 100644 Binary files a/test/widgets/token_selector_modal/goldens/token_selector_modal_token_groups_tooltip.png and b/test/widgets/token_selector_modal/goldens/token_selector_modal_token_groups_tooltip.png differ diff --git a/test/widgets/token_selector_modal/token_selector_modal_cubit_test.dart b/test/widgets/token_selector_modal/token_selector_modal_cubit_test.dart index 6d0227a..8e01db0 100644 --- a/test/widgets/token_selector_modal/token_selector_modal_cubit_test.dart +++ b/test/widgets/token_selector_modal/token_selector_modal_cubit_test.dart @@ -3,7 +3,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:web3kit/web3kit.dart'; import 'package:zup_app/app/app_cubit/app_cubit.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/dtos/token_list_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/repositories/tokens_repository.dart'; @@ -187,7 +187,7 @@ void main() { it should not emit the searchSuccess state when it completes""", () async { const requestDuration = Duration(milliseconds: 1); - final futureResult = []; + final futureResult = []; when( () => tokensRepository.searchToken(any(), any()), @@ -228,7 +228,7 @@ void main() { test( "When calling `searchTokens` and the repository returns success it should emit the searchSuccess state", () async { - final searchResult = [TokenDto.fixture(), TokenDto.fixture()]; + final searchResult = [MultiChainTokenDto.fixture(), MultiChainTokenDto.fixture()]; when(() => tokensRepository.searchToken(any(), any())).thenAnswer((_) async => searchResult); await sut.searchToken("dale"); @@ -314,8 +314,8 @@ void main() { it should emit the search not found state""", () async { final returnedList = [ - TokenDto.fixture().copyWith(name: "", symbol: "", logoUrl: "", addresses: {}), - TokenDto.fixture().copyWith(name: "", symbol: "", decimals: {}, logoUrl: "", addresses: {}), + MultiChainTokenDto.fixture().copyWith(name: "", symbol: "", logoUrl: "", addresses: {}), + MultiChainTokenDto.fixture().copyWith(name: "", symbol: "", decimals: {}, logoUrl: "", addresses: {}), ]; when(() => tokensRepository.searchToken(any(), any())).thenAnswer((_) async => returnedList); @@ -330,10 +330,10 @@ void main() { """When calling 'searchToken' and one token in the list returned has symbol and name, it should emit the search sucesss state, without the tokens without name and symbol""", () async { - final namedToken = TokenDto.fixture(); + final namedToken = MultiChainTokenDto.fixture(); final returnedList = [ - TokenDto.fixture().copyWith(name: "", symbol: "", logoUrl: "", addresses: {}), - TokenDto.fixture().copyWith(name: "", symbol: "", logoUrl: "", addresses: {}), + MultiChainTokenDto.fixture().copyWith(name: "", symbol: "", logoUrl: "", addresses: {}), + MultiChainTokenDto.fixture().copyWith(name: "", symbol: "", logoUrl: "", addresses: {}), namedToken, ]; diff --git a/test/widgets/token_selector_modal/token_selector_modal_test.dart b/test/widgets/token_selector_modal/token_selector_modal_test.dart index 0c611e2..3d4d555 100644 --- a/test/widgets/token_selector_modal/token_selector_modal_test.dart +++ b/test/widgets/token_selector_modal/token_selector_modal_test.dart @@ -4,7 +4,7 @@ import 'package:golden_toolkit/golden_toolkit.dart'; import 'package:mocktail/mocktail.dart'; import 'package:zup_app/app/app_cubit/app_cubit.dart'; import 'package:zup_app/core/debouncer.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; +import 'package:zup_app/core/dtos/multi_chain_token_dto.dart'; import 'package:zup_app/core/dtos/token_group_dto.dart'; import 'package:zup_app/core/dtos/token_list_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; @@ -13,8 +13,7 @@ import 'package:zup_app/core/repositories/tokens_repository.dart'; import 'package:zup_app/widgets/token_group_card.dart'; import 'package:zup_app/widgets/token_selector_modal/token_selector_modal.dart'; import 'package:zup_app/widgets/token_selector_modal/token_selector_modal_cubit.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; -import 'package:zup_core/zup_core.dart'; +import 'package:zup_core/test_utils.dart'; import 'package:zup_ui_kit/zup_ui_kit.dart'; import '../../golden_config.dart'; @@ -32,7 +31,7 @@ void main() { cubit = TokenSelectorModalCubitMock(); inject.registerFactory(() => cubit); - inject.registerFactory(() => mockZupCachedImage()); + inject.registerFactory(() => mockZupNetworkImage()); inject.registerFactory(() => Debouncer(milliseconds: 0)); inject.registerFactory(() => appCubit); @@ -47,7 +46,7 @@ void main() { tearDown(() => inject.reset()); Future goldenBuilder({ - Function(TokenDto)? onSelectToken, + Function(MultiChainTokenDto)? onSelectToken, Function(TokenGroupDto)? onSelectTokenGroup, }) async => await goldenDeviceBuilder( Builder( @@ -200,7 +199,7 @@ void main() { "When the state is search success, it should show the search success state", goldenFileName: "token_selector_modal_search_success", (tester) async { - final tokenList = List.generate(10, (_) => TokenDto.fixture()); + final tokenList = List.generate(10, (_) => MultiChainTokenDto.fixture()); when(() => cubit.state).thenReturn(TokenSelectorModalState.searchSuccess(tokenList)); @@ -237,7 +236,7 @@ void main() { tester, ) async { final tokenList = TokenListDto.fixture(); - TokenDto? selectedToken; + MultiChainTokenDto? selectedToken; when(() => cubit.state).thenReturn(TokenSelectorModalState.success(tokenList)); diff --git a/test/widgets/yield_card_test.dart b/test/widgets/yield_card_test.dart index 38b40b0..b7862e8 100644 --- a/test/widgets/yield_card_test.dart +++ b/test/widgets/yield_card_test.dart @@ -2,21 +2,22 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:golden_toolkit/golden_toolkit.dart'; +import 'package:zup_app/core/dtos/liquidity_pool_dto.dart'; +import 'package:zup_app/core/dtos/pool_stats_dto.dart'; import 'package:zup_app/core/dtos/protocol_dto.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; -import 'package:zup_app/core/enums/yield_timeframe.dart'; +import 'package:zup_app/core/dtos/single_chain_token_dto.dart'; +import 'package:zup_app/core/enums/pool_data_timeframe.dart'; import 'package:zup_app/core/injections.dart'; import 'package:zup_app/widgets/yield_card.dart'; -import 'package:zup_app/widgets/zup_cached_image.dart'; -import 'package:zup_core/extensions/widget_tester_extension.dart'; +import 'package:zup_core/test_utils.dart'; +import 'package:zup_ui_kit/zup_ui_kit.dart'; import '../golden_config.dart'; import '../mocks.dart'; void main() { setUp(() { - inject.registerFactory(() => mockZupCachedImage()); + inject.registerLazySingleton(() => mockZupNetworkImage()); inject.registerFactory(() => false, instanceName: InjectInstanceNames.infinityAnimationAutoPlay); }); @@ -24,22 +25,24 @@ void main() { Future goldenBuilder({ bool isHotestYield = true, - YieldDto? yieldPool, - YieldTimeFrame? yieldTimeFrame, + LiquidityPoolDto? yieldPool, + PoolDataTimeframe? yieldTimeFrame, bool snapshotDarkMode = false, bool showYieldTimeframe = false, + ZupIconButton? secondaryButton, }) async => await goldenDeviceBuilder( darkMode: snapshotDarkMode, Center( child: SizedBox( - height: 310, + height: 315, width: 340, child: YieldCard( showTimeframe: showYieldTimeframe, showHotestYieldAnimation: false, - yieldPool: yieldPool ?? YieldDto.fixture(), - yieldTimeFrame: yieldTimeFrame ?? YieldTimeFrame.day, - mainButton: const SizedBox(), + yieldPool: yieldPool ?? LiquidityPoolDto.fixture(), + yieldTimeFrame: yieldTimeFrame ?? PoolDataTimeframe.day, + secondaryButton: secondaryButton, + mainButton: ZupPrimaryButton(title: "Main Action", onPressed: (buttonContext) {}, height: 45), ), ), ), @@ -50,8 +53,10 @@ void main() { it should show the day yield from the passed yield pool""", goldenFileName: "yield_card_day_timeframe", (tester) async { - final pool = YieldDto.fixture().copyWith(yield24h: 12518721); - await tester.pumpDeviceBuilder(await goldenBuilder(yieldTimeFrame: YieldTimeFrame.day, yieldPool: pool)); + final pool = LiquidityPoolDto.fixture().copyWith( + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 12518721), + ); + await tester.pumpDeviceBuilder(await goldenBuilder(yieldTimeFrame: PoolDataTimeframe.day, yieldPool: pool)); }, ); @@ -60,8 +65,10 @@ void main() { it should show the week yield from the passed yield pool""", goldenFileName: "yield_card_week_timeframe", (tester) async { - final pool = YieldDto.fixture().copyWith(yield7d: 111122111); - await tester.pumpDeviceBuilder(await goldenBuilder(yieldTimeFrame: YieldTimeFrame.week, yieldPool: pool)); + final pool = LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 111122111), + ); + await tester.pumpDeviceBuilder(await goldenBuilder(yieldTimeFrame: PoolDataTimeframe.week, yieldPool: pool)); }, ); @@ -70,8 +77,10 @@ void main() { it should show the month yield from the passed yield pool""", goldenFileName: "yield_card_month_timeframe", (tester) async { - final pool = YieldDto.fixture().copyWith(yield30d: 991); - await tester.pumpDeviceBuilder(await goldenBuilder(yieldTimeFrame: YieldTimeFrame.month, yieldPool: pool)); + final pool = LiquidityPoolDto.fixture().copyWith( + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 991), + ); + await tester.pumpDeviceBuilder(await goldenBuilder(yieldTimeFrame: PoolDataTimeframe.month, yieldPool: pool)); }, ); @@ -80,8 +89,12 @@ void main() { it should show the three months yield from the passed yield pool""", goldenFileName: "yield_card_three_months_timeframe", (tester) async { - final pool = YieldDto.fixture().copyWith(yield90d: 654); - await tester.pumpDeviceBuilder(await goldenBuilder(yieldTimeFrame: YieldTimeFrame.threeMonth, yieldPool: pool)); + final pool = LiquidityPoolDto.fixture().copyWith( + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 654), + ); + await tester.pumpDeviceBuilder( + await goldenBuilder(yieldTimeFrame: PoolDataTimeframe.threeMonth, yieldPool: pool), + ); }, ); @@ -98,7 +111,7 @@ void main() { explaining that the pool is at n blockchain""", goldenFileName: "yield_card_blockchain_tooltip_hover", (tester) async { - final yieldPool = YieldDto.fixture(); + final yieldPool = LiquidityPoolDto.fixture(); await tester.pumpDeviceBuilder(await goldenBuilder(yieldPool: yieldPool)); await tester.hover(find.byKey(Key("yield-card-network-${yieldPool.network.label}"))); @@ -111,7 +124,12 @@ void main() { explaining the yield percent, and showing other timesframes yields""", goldenFileName: "yield_card_yield_tooltip_hover", (tester) async { - final yieldPool = YieldDto.fixture().copyWith(yield24h: 1212, yield7d: 2919, yield30d: 9824, yield90d: 1111); + final yieldPool = LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 2919), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 9824), + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1111), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1212), + ); await tester.pumpDeviceBuilder(await goldenBuilder(yieldPool: yieldPool)); await tester.hover(find.byKey(Key("yield-breakdown-tooltip-${yieldPool.poolAddress}"))); @@ -126,7 +144,12 @@ void main() { (tester) async { debugDefaultTargetPlatformOverride = TargetPlatform.android; - final yieldPool = YieldDto.fixture().copyWith(yield24h: 1212, yield7d: 2919, yield30d: 9824, yield90d: 1111); + final yieldPool = LiquidityPoolDto.fixture().copyWith( + total7dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 2919), + total30dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 9824), + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1111), + total24hStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 1212), + ); await tester.pumpDeviceBuilder(await goldenBuilder(yieldPool: yieldPool)); await tester.hover(find.byKey(Key("yield-card-yield-${yieldPool.poolAddress}"))); @@ -140,7 +163,7 @@ void main() { "When the tvl decimals is greater than 2, the tvl should be compact", goldenFileName: "yield_card_compacte_tvl", (tester) async { - final pool = YieldDto.fixture().copyWith(totalValueLockedUSD: 112152871.219201); + final pool = LiquidityPoolDto.fixture().copyWith(totalValueLockedUSD: 112152871.219201); await tester.pumpDeviceBuilder(await goldenBuilder(yieldPool: pool)); }, ); @@ -149,7 +172,7 @@ void main() { "When the protocol name is too big, it add a overflow ellipsis", goldenFileName: "yield_card_overflow_protocol_name", (tester) async { - final pool = YieldDto.fixture().copyWith( + final pool = LiquidityPoolDto.fixture().copyWith( protocol: ProtocolDto.fixture().copyWith(name: "Lorem ipsum dolor sit amet consectetur adipiscing elit"), ); await tester.pumpDeviceBuilder(await goldenBuilder(yieldPool: pool)); @@ -160,9 +183,13 @@ void main() { "When the token symbol pass 8 chars, it should be overflowed with an ellipsis", goldenFileName: "yield_card_overflow_token_symbol", (tester) async { - final pool = YieldDto.fixture().copyWith( - token0: TokenDto.fixture().copyWith(symbol: "Lorem ipsum dolor sit amet consectetur adipiscing elit"), - token1: TokenDto.fixture().copyWith(symbol: "elit adipiscing consectetur amet sit dolor ipsum Lorem"), + final pool = LiquidityPoolDto.fixture().copyWith( + token0: SingleChainTokenDto.fixture().copyWith( + symbol: "Lorem ipsum dolor sit amet consectetur adipiscing elit", + ), + token1: SingleChainTokenDto.fixture().copyWith( + symbol: "elit adipiscing consectetur amet sit dolor ipsum Lorem", + ), ); await tester.pumpDeviceBuilder(await goldenBuilder(yieldPool: pool)); }, @@ -172,9 +199,23 @@ void main() { "When passing 'showYieldTimframe' true, it should show the timeframe of the yield in the card", goldenFileName: "yield_card_show_yield_timeframe", (tester) async { - final pool = YieldDto.fixture().copyWith(yield90d: 654); + final pool = LiquidityPoolDto.fixture().copyWith( + total90dStats: PoolTotalStatsDTO.fixture().copyWith(yearlyYield: 654), + ); await tester.pumpDeviceBuilder( - await goldenBuilder(yieldTimeFrame: YieldTimeFrame.threeMonth, yieldPool: pool, showYieldTimeframe: true), + await goldenBuilder(yieldTimeFrame: PoolDataTimeframe.threeMonth, yieldPool: pool, showYieldTimeframe: true), + ); + }, + ); + + zGoldenTest( + "When passing a secondary button, it should be displayed in the card", + goldenFileName: "yield_card_secondary_button", + (tester) async { + await tester.pumpDeviceBuilder( + await goldenBuilder( + secondaryButton: ZupIconButton(icon: const Icon(Icons.place), onPressed: (_) {}), + ), ); }, ); diff --git a/web/index.html b/web/index.html index 4624d2b..9259ecd 100644 --- a/web/index.html +++ b/web/index.html @@ -1,9 +1,17 @@ + + +