diff --git a/lib/app/app_cubit/app_cubit.dart b/lib/app/app_cubit/app_cubit.dart index 564dc7f..7df41ef 100644 --- a/lib/app/app_cubit/app_cubit.dart +++ b/lib/app/app_cubit/app_cubit.dart @@ -15,7 +15,7 @@ class AppCubit extends Cubit { _isTestnetMode = _cache.getTestnetMode(); if (_isTestnetMode) { - _selectedNetwork = Networks.sepolia; + updateAppNetwork(AppNetworks.sepolia); emit(AppState.testnetModeChanged(_isTestnetMode)); } } @@ -23,14 +23,15 @@ class AppCubit extends Cubit { final Wallet _wallet; final Cache _cache; - Networks _selectedNetwork = Networks.mainnet; + AppNetworks _selectedNetwork = AppNetworks.allNetworks; bool _isTestnetMode = false; - final StreamController _selectedNetworkStreamController = StreamController.broadcast(); + final StreamController _selectedNetworkStreamController = StreamController.broadcast(); - Stream get selectedNetworkStream => _selectedNetworkStreamController.stream; + Stream get selectedNetworkStream => _selectedNetworkStreamController.stream; - Networks get selectedNetwork => _selectedNetwork; + AppNetworks get selectedNetwork => _selectedNetwork; + int get currentChainId => _selectedNetwork.chainId; bool get isTestnetMode => _isTestnetMode; void _setupStreams() { @@ -47,7 +48,7 @@ class AppCubit extends Cubit { } } - void updateAppNetwork(Networks newNetwork) async { + void updateAppNetwork(AppNetworks newNetwork) async { if (newNetwork == _selectedNetwork) return; emit(AppState.networkChanged(newNetwork)); @@ -60,7 +61,7 @@ class AppCubit extends Cubit { Future toggleTestnetMode() async { _isTestnetMode = !_isTestnetMode; - updateAppNetwork(isTestnetMode ? Networks.sepolia : Networks.mainnet); + updateAppNetwork(isTestnetMode ? AppNetworks.sepolia : AppNetworks.allNetworks); await _cache.saveTestnetMode(isTestnetMode: _isTestnetMode); try { diff --git a/lib/app/app_cubit/app_state.dart b/lib/app/app_cubit/app_state.dart index 38022e9..4cb7c12 100644 --- a/lib/app/app_cubit/app_state.dart +++ b/lib/app/app_cubit/app_state.dart @@ -4,6 +4,6 @@ part of 'app_cubit.dart'; class AppState { const factory AppState.standard() = _Standard; - const factory AppState.networkChanged(Networks newNetwork) = _NetworkChanged; + const factory AppState.networkChanged(AppNetworks newNetwork) = _NetworkChanged; const factory AppState.testnetModeChanged(bool isTestnetMode) = _TestnetModeChanged; } diff --git a/lib/app/create/create_page_select_tokens_stage.dart b/lib/app/create/create_page_select_tokens_stage.dart index 28b858a..1ca78bf 100644 --- a/lib/app/create/create_page_select_tokens_stage.dart +++ b/lib/app/create/create_page_select_tokens_stage.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:web3kit/core/core.dart'; import 'package:zup_app/app/app_cubit/app_cubit.dart'; import 'package:zup_app/app/create/widgets/create_page_settings_dropdown.dart'; import 'package:zup_app/core/cache.dart'; @@ -28,9 +27,7 @@ class _CreatePageState extends State with DeviceInf final navigator = inject(); final cache = inject(); - late final token0SelectorController = TokenSelectorButtonController( - initialSelectedToken: appCubit.selectedNetwork.nativeCurrencyTokenDto, - ); + late final token0SelectorController = TokenSelectorButtonController(initialSelectedToken: null); final token1SelectorController = TokenSelectorButtonController(initialSelectedToken: null); StreamSubscription? _token0SelectorStreamSubscription; StreamSubscription? _token1SelectorStreamSubscription; @@ -38,19 +35,10 @@ class _CreatePageState extends State with DeviceInf bool areTokensEqual(TokenDto? token0, TokenDto? token1) { if (token0 == null || token1 == null) return false; - if (token0.address == token1.address) return true; - // Note: If implementing all networks feature, this check should be refactored to work with all networks, - //as all networks network does not have a native token or a wrapped native token - if (token0.address.lowercasedEquals(appCubit.selectedNetwork.wrappedNative.address.toLowerCase()) && - token1.address.lowercasedEquals(EthereumConstants.zeroAddress)) { - return true; - } + if (appCubit.selectedNetwork.isAllNetworks) return token0.internalId == token1.internalId; - // Note: If implementing all networks feature, this check should be refactored to work with all networks, - //as all networks network does not have a native token or a wrapped native token - if (token1.address.lowercasedEquals(appCubit.selectedNetwork.wrappedNative.address.toLowerCase()) && - token0.address.lowercasedEquals(EthereumConstants.zeroAddress)) { + if (token0.addresses[appCubit.currentChainId] == token1.addresses[appCubit.currentChainId]) { return true; } @@ -60,8 +48,20 @@ class _CreatePageState extends State with DeviceInf @override void initState() { _selectedNetworkStreamSubscription = appCubit.selectedNetworkStream.listen((network) { - token0SelectorController.changeToken(network.nativeCurrencyTokenDto); - token1SelectorController.changeToken(null); + if (network.isAllNetworks) { + if (token0SelectorController.selectedToken?.internalId == null) token0SelectorController.changeToken(null); + if (token1SelectorController.selectedToken?.internalId == null) token1SelectorController.changeToken(null); + + return; + } + + if (token0SelectorController.selectedToken?.addresses[network.chainId] == null) { + token0SelectorController.changeToken(null); + } + + if (token1SelectorController.selectedToken?.addresses[network.chainId] == null) { + token1SelectorController.changeToken(null); + } }); _token0SelectorStreamSubscription = token0SelectorController.selectedTokenStream.listen((token) { @@ -75,6 +75,7 @@ class _CreatePageState extends State with DeviceInf return token0SelectorController.changeToken(null); } }); + super.initState(); } @@ -173,6 +174,7 @@ class _CreatePageState extends State with DeviceInf stream: token1SelectorController.selectedTokenStream, builder: (context, _) { return ZupPrimaryButton( + key: const Key("search-button"), height: 50, fixedIcon: true, alignCenter: true, @@ -181,11 +183,17 @@ class _CreatePageState extends State with DeviceInf icon: Assets.icons.sparkleMagnifyingglass.svg(), onPressed: token0SelectorController.selectedToken != null && token1SelectorController.selectedToken != null - ? () => navigator.navigateToDeposit( - token0SelectorController.selectedToken!.address, - token1SelectorController.selectedToken!.address, + ? () { + return navigator.navigateToDeposit( + appCubit.selectedNetwork.isAllNetworks + ? token0SelectorController.selectedToken!.internalId! + : token0SelectorController.selectedToken!.addresses[appCubit.currentChainId]!, + appCubit.selectedNetwork.isAllNetworks + ? token1SelectorController.selectedToken!.internalId! + : token1SelectorController.selectedToken!.addresses[appCubit.currentChainId]!, appCubit.selectedNetwork, - ) + ); + } : null, mainAxisSize: MainAxisSize.max, ); diff --git a/lib/app/create/deposit/deposit_cubit.dart b/lib/app/create/deposit/deposit_cubit.dart index db4a8fe..d8dd60e 100644 --- a/lib/app/create/deposit/deposit_cubit.dart +++ b/lib/app/create/deposit/deposit_cubit.dart @@ -45,11 +45,13 @@ class DepositCubit extends Cubit with KeysMixin, V3PoolConversorsM BigInt? _latestPoolTick; YieldDto? _selectedYield; + YieldTimeFrame? _selectedYieldTimeframe; late final Stream selectedYieldStream = _selectedYieldStreamController.stream; late final Stream poolTickStream = _pooltickStreamController.stream; YieldDto? get selectedYield => _selectedYield; + YieldTimeFrame? get selectedYieldTimeframe => _selectedYieldTimeframe; BigInt? get latestPoolTick => _latestPoolTick; DepositSettingsDto get depositSettings => _cache.getDepositSettings(); PoolSearchSettingsDto get poolSearchSettings => _cache.getPoolSearchSettings(); @@ -63,24 +65,31 @@ class DepositCubit extends Cubit with KeysMixin, V3PoolConversorsM } Future getBestPools({ - required String token0Address, - required String token1Address, + required String token0AddressOrId, + required String token1AddressOrId, bool ignoreMinLiquidity = false, }) async { try { _zupAnalytics.logSearch( - token0: token0Address, - token1: token1Address, + token0: token0AddressOrId, + token1: token1AddressOrId, network: _appCubit.selectedNetwork.label, ); emit(const DepositState.loading()); - final yields = await _yieldRepository.getYields( - token0Address: token0Address, - token1Address: token1Address, - network: _appCubit.selectedNetwork, - minTvlUsd: ignoreMinLiquidity ? 0 : poolSearchSettings.minLiquidityUSD, - ); + final yields = _appCubit.selectedNetwork.isAllNetworks + ? await _yieldRepository.getAllNetworksYield( + token0InternalId: token0AddressOrId, + token1InternalId: token1AddressOrId, + minTvlUsd: ignoreMinLiquidity ? 0 : poolSearchSettings.minLiquidityUSD, + testnetMode: _appCubit.isTestnetMode, + ) + : await _yieldRepository.getSingleNetworkYield( + token0Address: token0AddressOrId, + token1Address: token1AddressOrId, + network: _appCubit.selectedNetwork, + minTvlUsd: ignoreMinLiquidity ? 0 : poolSearchSettings.minLiquidityUSD, + ); if (yields.isEmpty) { return emit( @@ -94,8 +103,9 @@ class DepositCubit extends Cubit with KeysMixin, V3PoolConversorsM } } - Future selectYield(YieldDto? yieldDto) async { + Future selectYield(YieldDto? yieldDto, YieldTimeFrame? yieldTimeFrame) async { _selectedYield = yieldDto; + _selectedYieldTimeframe = yieldTimeFrame; _selectedYieldStreamController.add(selectedYield); if (selectedYield != null) await getSelectedPoolTick(); @@ -121,7 +131,7 @@ class DepositCubit extends Cubit with KeysMixin, V3PoolConversorsM _latestPoolTick = slot0.tick; } - Future getWalletTokenAmount(String tokenAddress, {required Networks network}) async { + Future getWalletTokenAmount(String tokenAddress, {required AppNetworks network}) async { if (_wallet.signer == null) return 0.0; final walletAddress = await _wallet.signer!.address; diff --git a/lib/app/create/deposit/deposit_page.dart b/lib/app/create/deposit/deposit_page.dart index bbabb63..3ac5c24 100644 --- a/lib/app/create/deposit/deposit_page.dart +++ b/lib/app/create/deposit/deposit_page.dart @@ -35,9 +35,7 @@ import 'package:zup_app/gen/assets.gen.dart'; import 'package:zup_app/l10n/gen/app_localizations.dart'; import 'package:zup_app/widgets/yield_card.dart'; import 'package:zup_app/widgets/zup_page_title.dart'; -import 'package:zup_core/extensions/extensions.dart'; -import 'package:zup_core/mixins/device_info_mixin.dart'; -import 'package:zup_core/zup_singleton_cache.dart'; +import 'package:zup_core/zup_core.dart'; import 'package:zup_ui_kit/zup_ui_kit.dart'; Route routeBuilder(BuildContext context, RouteSettings settings) { @@ -106,8 +104,9 @@ class _DepositPageState extends State bool isBaseTokenAmountUserInput = false; double minPrice = 0; double maxPrice = 0; - late bool depositWithNativeToken = - token0Address == EthereumConstants.zeroAddress || token1Address == EthereumConstants.zeroAddress; + + late bool depositWithNativeToken = true; + late Slippage selectedSlippage = _cubit.depositSettings.slippage; late Duration selectedDeadline = _cubit.depositSettings.deadline; @@ -155,8 +154,8 @@ class _DepositPageState extends State calculateDepositTokensAmount(); } - void selectYield(YieldDto? yieldDto) async { - _cubit.selectYield(yieldDto).then((_) => calculateDepositTokensAmount()); + void selectYield(YieldDto? yieldDto, YieldTimeFrame? yieldTimeFrame) async { + _cubit.selectYield(yieldDto, yieldTimeFrame).then((_) => calculateDepositTokensAmount()); if (yieldDto != null) { WidgetsBinding.instance.addPostFrameCallback((_) { @@ -243,12 +242,12 @@ class _DepositPageState extends State Future<({String title, Widget? icon, Function()? onPressed})> depositButtonState() async { final userWalletBaseTokenAmount = await _cubit.getWalletTokenAmount( - baseToken.address, + baseToken.addresses[_cubit.selectedYield!.network.chainId]!, network: _cubit.selectedYield!.network, ); final userWalletQuoteTokenAmount = await _cubit.getWalletTokenAmount( - quoteToken.address, + quoteToken.addresses[_cubit.selectedYield!.network.chainId]!, network: _cubit.selectedYield!.network, ); @@ -292,6 +291,7 @@ class _DepositPageState extends State onPressed: () { PreviewDepositModal( key: const Key("preview-deposit-modal"), + yieldTimeFrame: _cubit.selectedYieldTimeframe!, depositWithNativeToken: depositWithNativeToken, deadline: selectedDeadline, maxSlippage: selectedSlippage, @@ -322,14 +322,14 @@ class _DepositPageState extends State final currentNetworkFromUrl = _navigator.getParam(ZupNavigatorPaths.deposit.routeParamsName?.param3 ?? ""); if (currentNetworkFromUrl?.isNotEmpty ?? false) { - final currentNetwork = Networks.fromValue(currentNetworkFromUrl!); + final currentNetwork = AppNetworks.fromValue(currentNetworkFromUrl!); if (currentNetwork != null && currentNetwork != _appCubit.selectedNetwork) { _appCubit.updateAppNetwork(currentNetwork); } } WidgetsBinding.instance.addPostFrameCallback((_) { - _cubit.getBestPools(token0Address: token0Address, token1Address: token1Address); + _cubit.getBestPools(token0AddressOrId: token0Address, token1AddressOrId: token1Address); }); super.initState(); @@ -472,8 +472,8 @@ class _DepositPageState extends State child: TextButton( key: const Key("search-all-pools-button"), onPressed: () => _cubit.getBestPools( - token0Address: token0Address, - token1Address: token1Address, + token0AddressOrId: token0Address, + token1AddressOrId: token1Address, ignoreMinLiquidity: true, ), style: ButtonStyle( @@ -503,8 +503,8 @@ class _DepositPageState extends State helpButtonTitle: S.of(context).letsGiveItAnotherShot, helpButtonIcon: Assets.icons.arrowClockwise.svg(), onHelpButtonTap: () => _cubit.getBestPools( - token0Address: token0Address, - token1Address: token1Address, + token0AddressOrId: token0Address, + token1AddressOrId: token1Address, ), ), ), @@ -539,43 +539,40 @@ class _DepositPageState extends State ); Widget _buildYieldSelectionSector(YieldsDto yields) { - final best24hYield = yields.timeframedYields.best24hYields.firstOrNull; - final best30dYield = yields.timeframedYields.best30dYields.firstOrNull; - final best90dYield = yields.timeframedYields.best90dYields.firstOrNull; + final best30dYield = yields.best30dYield; + final best24hYield = yields.best24hYield; + final best90dYield = yields.best90dYield; final List yieldCards = [ - if (best24hYield != null) - YieldCard( - key: const Key("yield-card-24h"), - yield: best24hYield, - onChangeSelection: (yield) { - selectYield(yield); - }, - isSelected: _cubit.selectedYield.equals(best24hYield), - timeFrame: YieldTimeFrame.day, - ), + YieldCard( + key: const Key("yield-card-24h"), + currentYield: best24hYield, + onChangeSelection: (yield) { + selectYield(yield, YieldTimeFrame.day); + }, + isSelected: _cubit.selectedYield.equals(best24hYield) && (_cubit.selectedYieldTimeframe?.isDay ?? false), + timeFrame: YieldTimeFrame.day, + ), const SizedBox(width: 8, height: 20), - if (best30dYield != null) - YieldCard( - key: const Key("yield-card-30d"), - yield: best30dYield, - onChangeSelection: (yield) { - selectYield(yield); - }, - isSelected: _cubit.selectedYield.equals(best30dYield), - timeFrame: YieldTimeFrame.month, - ), + YieldCard( + key: const Key("yield-card-30d"), + currentYield: best30dYield, + onChangeSelection: (yield) { + selectYield(yield, YieldTimeFrame.month); + }, + isSelected: _cubit.selectedYield.equals(best30dYield) && (_cubit.selectedYieldTimeframe?.isMonth ?? false), + timeFrame: YieldTimeFrame.month, + ), const SizedBox(width: 8, height: 20), - if (best90dYield != null) - YieldCard( - key: const Key("yield-card-90d"), - yield: best90dYield, - onChangeSelection: (yield) { - selectYield(yield); - }, - isSelected: _cubit.selectedYield.equals(best90dYield), - timeFrame: YieldTimeFrame.threeMonth, - ), + YieldCard( + key: const Key("yield-card-90d"), + currentYield: best90dYield, + onChangeSelection: (yield) { + selectYield(yield, YieldTimeFrame.threeMonth); + }, + isSelected: _cubit.selectedYield.equals(best90dYield) && (_cubit.selectedYieldTimeframe?.isThreeMonth ?? false), + timeFrame: YieldTimeFrame.threeMonth, + ), ]; return Column( @@ -639,8 +636,8 @@ class _DepositPageState extends State child: TextButton( key: const Key("hide-show-all-pools-button"), onPressed: () => _cubit.getBestPools( - token0Address: token0Address, - token1Address: token1Address, + token0AddressOrId: token0Address, + token1AddressOrId: token1Address, ignoreMinLiquidity: yields.minLiquidityUSD > 0, ), style: ButtonStyle( @@ -853,27 +850,35 @@ class _DepositPageState extends State return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - _sectionTitle(S.of(context).depositPageDepositSectionTitle), - const Spacer(), - Text( - S.of(context).depositPageDepositWithNativeToken( - tokenSymbol: _cubit.selectedYield?.network.chainInfo.nativeCurrency!.symbol ?? "", - ), - style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w500), - ), - const SizedBox(width: 10), - ZupSwitch( - value: depositWithNativeToken, - onChanged: (value) => setState(() => depositWithNativeToken = value), - ), - ], - ), + if (baseToken.addresses[_cubit.selectedYield!.network.chainId]!.lowercasedEquals(_cubit + .selectedYield!.network.wrappedNative.addresses[_cubit.selectedYield!.network.chainId]!) || + quoteToken.addresses[_cubit.selectedYield!.network.chainId]!.lowercasedEquals( + _cubit.selectedYield!.network.wrappedNative.addresses[_cubit.selectedYield!.network.chainId]!, + )) + Row( + children: [ + _sectionTitle(S.of(context).depositPageDepositSectionTitle), + const Spacer(), + Text( + S.of(context).depositPageDepositWithNativeToken( + tokenSymbol: _cubit.selectedYield?.network.chainInfo.nativeCurrency!.symbol ?? "", + ), + style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w500), + ), + const SizedBox(width: 10), + ZupSwitch( + value: depositWithNativeToken, + onChanged: (value) => setState(() => depositWithNativeToken = value), + ), + ], + ), const SizedBox(height: 12), TokenAmountInputCard( key: const Key("base-token-input-card"), token: baseToken, + isNative: depositWithNativeToken && + baseToken.addresses[_cubit.selectedYield!.network.chainId]!.lowercasedEquals(_cubit + .selectedYield!.network.wrappedNative.addresses[_cubit.selectedYield!.network.chainId]!), onRefreshBalance: () => setState(() {}), disabledText: () { if (!isBaseTokenNeeded) { @@ -900,6 +905,9 @@ class _DepositPageState extends State TokenAmountInputCard( key: const Key("quote-token-input-card"), token: quoteToken, + isNative: depositWithNativeToken && + quoteToken.addresses[_cubit.selectedYield!.network.chainId]!.lowercasedEquals(_cubit + .selectedYield!.network.wrappedNative.addresses[_cubit.selectedYield!.network.chainId]!), onRefreshBalance: () => setState(() {}), disabledText: () { if (!isQuoteTokenNeeded) { diff --git a/lib/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal.dart b/lib/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal.dart index dbe2e4e..f7855a8 100644 --- a/lib/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal.dart +++ b/lib/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal.dart @@ -37,9 +37,11 @@ class PreviewDepositModal extends StatefulWidget with DeviceInfoMixin { required this.deadline, required this.maxSlippage, required this.depositWithNativeToken, + required this.yieldTimeFrame, }); final YieldDto currentYield; + final YieldTimeFrame yieldTimeFrame; final bool isReversed; final ({double price, bool isInfinity}) minPrice; final ({double price, bool isInfinity}) maxPrice; @@ -80,6 +82,7 @@ class PreviewDepositModal extends StatefulWidget with DeviceInfoMixin { maxPrice: maxPrice, currentYield: currentYield, isReversed: isReversed, + yieldTimeFrame: yieldTimeFrame, ), ), ); @@ -175,6 +178,18 @@ class _PreviewDepositModalState extends State with V3PoolCo return isReversedLocal ? price().priceAsQuoteToken : price().priceAsBaseToken; } + num get yieldTimeframed { + if (widget.yieldTimeFrame.isDay) { + return widget.currentYield.yield24h; + } + + if (widget.yieldTimeFrame.isMonth) { + return widget.currentYield.yield30d; + } + + return widget.currentYield.yield90d; + } + ({bool minPrice, bool maxPrice, bool any}) get isOutOfRange { final isMinPriceOutOfRange = !widget.minPrice.isInfinity && (minPrice) > currentPrice; final isMaxPriceOutOfRanfe = !widget.maxPrice.isInfinity && (maxPrice) < currentPrice; @@ -547,8 +562,9 @@ class _PreviewDepositModalState extends State with V3PoolCo const SizedBox(height: 20), _fieldColumn( spacing: 0, - title: S.of(context).previewDepositModalYearlyYield, - value: widget.currentYield.yearlyYield.formatPercent, + title: + "${S.of(context).previewDepositModalYearlyYield} (${widget.yieldTimeFrame.label(context)})", + value: yieldTimeframed.formatPercent, ), const SizedBox(height: 10), const ZupDivider(), diff --git a/lib/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit.dart b/lib/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit.dart index 40b68d3..42b308e 100644 --- a/lib/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit.dart +++ b/lib/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_cubit.dart @@ -87,12 +87,16 @@ class PreviewDepositModalCubit extends Cubit with V3Po Future approveToken(TokenDto token, BigInt value) async { try { + final tokenAddressInNetwork = token.addresses[_yield.network.chainId]!; emit(PreviewDepositModalState.approvingToken(token.symbol)); await _maybeSwitchNetwork(); - final contract = _erc20.fromSigner(contractAddress: token.address, signer: _wallet.signer!); - final tx = await contract.approve(spender: _yield.protocol.positionManager, value: value); + final contract = _erc20.fromSigner( + contractAddress: tokenAddressInNetwork, + signer: _wallet.signer!, + ); + final tx = await contract.approve(spender: _yield.positionManagerAddress, value: value); emit(PreviewDepositModalState.waitingTransaction(txId: tx.hash, type: WaitingTransactionType.approve)); @@ -101,8 +105,8 @@ class PreviewDepositModalCubit extends Cubit with V3Po try { await _getTokensAllowance(canThrow: true); } catch (e) { - if (_yield.token0.address == token.address) _token0Allowance = value; - if (_yield.token1.address == token.address) _token1Allowance = value; + if (_yield.token0.addresses[_yield.network.chainId] == tokenAddressInNetwork) _token0Allowance = value; + if (_yield.token1.addresses[_yield.network.chainId] == tokenAddressInNetwork) _token1Allowance = value; } emit(PreviewDepositModalState.approveSuccess(txId: tx.hash, symbol: token.symbol)); @@ -135,7 +139,7 @@ class PreviewDepositModalCubit extends Cubit with V3Po await _maybeSwitchNetwork(); final positionManagerContract = _uniswapPositionManager.fromSigner( - contractAddress: _yield.protocol.positionManager, + contractAddress: _yield.positionManagerAddress, signer: _wallet.signer!, ); @@ -196,8 +200,8 @@ class PreviewDepositModalCubit extends Cubit with V3Po tickLower: tickLower(), tickUpper: tickUpper(), fee: BigInt.from(_yield.feeTier), - token0: _yield.token0.address, - token1: _yield.token1.address, + token0: _yield.token0.addresses[_yield.network.chainId]!, + token1: _yield.token1.addresses[_yield.network.chainId]!, ), ); @@ -230,8 +234,8 @@ class PreviewDepositModalCubit extends Cubit with V3Po tickLower: tickLower(), tickUpper: tickUpper(), fee: BigInt.from(_yield.feeTier), - token0: _yield.token0.address, - token1: _yield.token1.address, + token0: _yield.token0.addresses[_yield.network.chainId]!, + token1: _yield.token1.addresses[_yield.network.chainId]!, ), ); }.call(); @@ -282,23 +286,23 @@ class PreviewDepositModalCubit extends Cubit with V3Po Future _getTokensAllowance({bool canThrow = false}) async { try { final token0contract = _erc20.fromRpcProvider( - contractAddress: _yield.token0.address, + contractAddress: _yield.token0.addresses[_yield.network.chainId]!, rpcUrl: _yield.network.rpcUrl, ); final token1contract = _erc20.fromRpcProvider( - contractAddress: _yield.token1.address, + contractAddress: _yield.token1.addresses[_yield.network.chainId]!, rpcUrl: _yield.network.rpcUrl, ); final token0Allowance = await token0contract.allowance( owner: await _wallet.signer!.address, - spender: _yield.protocol.positionManager, + spender: _yield.positionManagerAddress, ); final token1Allowance = await token1contract.allowance( owner: await _wallet.signer!.address, - spender: _yield.protocol.positionManager, + spender: _yield.positionManagerAddress, ); _token0Allowance = token0Allowance; diff --git a/lib/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card.dart b/lib/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card.dart index da8998e..b1dfd40 100644 --- a/lib/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card.dart +++ b/lib/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card.dart @@ -22,14 +22,16 @@ class TokenAmountInputCard extends StatefulWidget { this.disabledText, required this.network, this.onRefreshBalance, + this.isNative = false, }); final TokenDto token; - final Networks network; + final AppNetworks network; final TextEditingController controller; final Function(double value) onInput; final String? disabledText; final VoidCallback? onRefreshBalance; + final bool isNative; @override State createState() => _TokenAmountInputCardState(); @@ -41,9 +43,9 @@ class _TokenAmountInputCardState extends State with Single Wallet get wallet => inject(); ZupSingletonCache get zupSingletonCache => inject(); - late final TokenAmountCardUserBalanceCubit userBalanceCubit = TokenAmountCardUserBalanceCubit( + late TokenAmountCardUserBalanceCubit userBalanceCubit = TokenAmountCardUserBalanceCubit( wallet, - widget.token.address, + widget.token.addresses[widget.network.chainId]!, widget.network, zupSingletonCache, widget.onRefreshBalance, @@ -56,16 +58,27 @@ class _TokenAmountInputCardState extends State with Single refreshBalanceAnimationController = AnimationController(vsync: this, duration: const Duration(milliseconds: 100)); WidgetsBinding.instance.addPostFrameCallback((tester) { - if (wallet.signer != null) userBalanceCubit.getUserTokenAmount(); + if (wallet.signer != null) userBalanceCubit.getUserTokenAmount(isNative: widget.isNative); }); super.initState(); } @override void didUpdateWidget(covariant TokenAmountInputCard oldWidget) { + if (widget.isNative != oldWidget.isNative) { + WidgetsBinding.instance + .addPostFrameCallback((_) => userBalanceCubit.getUserTokenAmount(isNative: widget.isNative)); + + return super.didUpdateWidget(oldWidget); + } + if (widget.token != oldWidget.token) { WidgetsBinding.instance.addPostFrameCallback((_) { - userBalanceCubit.updateToken(widget.token.address); + userBalanceCubit.updateTokenAndNetwork( + widget.token.addresses[widget.network.chainId]!, + widget.network, + asNativeToken: widget.isNative, + ); }); super.didUpdateWidget(oldWidget); @@ -240,9 +253,11 @@ class _TokenAmountInputCardState extends State with Single onPressed: () async => state.mapOrNull( error: (_) async => await userBalanceCubit.getUserTokenAmount( ignoreCache: true, + isNative: widget.isNative, ), showUserBalance: (_) async => await userBalanceCubit.getUserTokenAmount( ignoreCache: true, + isNative: widget.isNative, ), ), ), diff --git a/lib/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_user_balance_cubit.dart b/lib/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_user_balance_cubit.dart index cef9872..7bc347b 100644 --- a/lib/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_user_balance_cubit.dart +++ b/lib/app/create/deposit/widgets/token_amount_input_card/token_amount_input_card_user_balance_cubit.dart @@ -19,9 +19,9 @@ class TokenAmountCardUserBalanceCubit extends Cubit updateToken(String tokenAddress) async { + Future updateTokenAndNetwork(String tokenAddress, AppNetworks network, {required bool asNativeToken}) async { _tokenAddress = tokenAddress; + _network = network; - if (_wallet.signer != null) await getUserTokenAmount(); + if (_wallet.signer != null) await getUserTokenAmount(isNative: asNativeToken); } - Future getUserTokenAmount({bool ignoreCache = false}) async { + Future getUserTokenAmount({bool ignoreCache = false, bool isNative = false}) async { try { emit(const TokenAmountCardUserBalanceState.loadingUserBalance()); userBalance = await _zupSingletonCache.run(() async { - return await _wallet.nativeOrTokenBalance(_tokenAddress, rpcUrl: _network.rpcUrl); + return await _wallet.nativeOrTokenBalance( + isNative ? EthereumConstants.zeroAddress : _tokenAddress, + rpcUrl: _network.rpcUrl, + ); }, key: userTokenBalanceCacheKey( tokenAddress: _tokenAddress, userAddress: await _wallet.signer!.address, + isNative: isNative, ), ignoreCache: ignoreCache, expiration: const Duration(minutes: 10)); diff --git a/lib/core/dtos/position_dto.dart b/lib/core/dtos/position_dto.dart index 6ab23f9..edfe577 100644 --- a/lib/core/dtos/position_dto.dart +++ b/lib/core/dtos/position_dto.dart @@ -15,7 +15,7 @@ class PositionDto with _$PositionDto { const factory PositionDto({ TokenDto? token0, TokenDto? token1, - @Default(null) Networks? network, + @Default(null) AppNetworks? network, @Default(PositionStatus.unknown) @JsonKey(unknownEnumValue: PositionStatus.unknown) PositionStatus status, @Default(null) ProtocolDto? protocol, @Default(0) num minRange, diff --git a/lib/core/dtos/protocol_dto.dart b/lib/core/dtos/protocol_dto.dart index 41671c7..78c7f44 100644 --- a/lib/core/dtos/protocol_dto.dart +++ b/lib/core/dtos/protocol_dto.dart @@ -12,7 +12,6 @@ class ProtocolDto with _$ProtocolDto { @Default("") String name, @Default("") String url, @Default("") String logo, - @Default("") String positionManager, }) = _ProtocolDto; factory ProtocolDto.fromJson(Map json) => _$ProtocolDtoFromJson(json); @@ -21,6 +20,5 @@ class ProtocolDto with _$ProtocolDto { name: "Uniswap", url: "https://app.uniswap.org/pool", logo: "https://raw.githubusercontent.com/trustwallet/assets/master/dapps/app.uniswap.org.png", - positionManager: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", ); } diff --git a/lib/core/dtos/token_dto.dart b/lib/core/dtos/token_dto.dart index af14931..0c0c15f 100644 --- a/lib/core/dtos/token_dto.dart +++ b/lib/core/dtos/token_dto.dart @@ -1,4 +1,5 @@ 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'; @@ -7,10 +8,11 @@ part 'token_dto.g.dart'; class TokenDto with _$TokenDto { @JsonSerializable(explicitToJson: true) const factory TokenDto({ + @JsonKey(name: "id") String? internalId, @Default("") String symbol, @Default("") String name, - @Default("") String address, @Default("") String logoUrl, + @Default({}) Map addresses, @Default(0) int decimals, }) = _TokenDto; @@ -18,10 +20,10 @@ class TokenDto with _$TokenDto { factory TokenDto.empty() => const TokenDto(); - factory TokenDto.fixture() => const TokenDto( + factory TokenDto.fixture() => TokenDto( symbol: 'WETH', name: 'Wrapped Ether', - address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + addresses: {AppNetworks.sepolia.chainId: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"}, logoUrl: 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png', ); diff --git a/lib/core/dtos/token_list_dto.dart b/lib/core/dtos/token_list_dto.dart deleted file mode 100644 index a397a31..0000000 --- a/lib/core/dtos/token_list_dto.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:zup_app/core/dtos/token_dto.dart'; - -part 'token_list_dto.freezed.dart'; -part 'token_list_dto.g.dart'; - -@freezed -class TokenListDto with _$TokenListDto { - const TokenListDto._(); - - @JsonSerializable(explicitToJson: true) - const factory TokenListDto({ - @Default([]) List mostUsedTokens, - @Default([]) List userTokens, - @Default([]) List popularTokens, - }) = _TokenListDto; - - factory TokenListDto.fromJson(Map json) => _$TokenListDtoFromJson(json); - - factory TokenListDto.empty() => const TokenListDto( - mostUsedTokens: [], - userTokens: [], - popularTokens: [], - ); - - factory TokenListDto.fixture() => TokenListDto( - mostUsedTokens: [ - TokenDto.fixture(), - TokenDto.fixture(), - TokenDto.fixture(), - TokenDto.fixture(), - TokenDto.fixture(), - TokenDto.fixture(), - ], - userTokens: [ - TokenDto.fixture().copyWith(), - ], - popularTokens: [ - TokenDto.fixture(), - ], - ); -} diff --git a/lib/core/dtos/yield_dto.dart b/lib/core/dtos/yield_dto.dart index ce1e137..eb58a19 100644 --- a/lib/core/dtos/yield_dto.dart +++ b/lib/core/dtos/yield_dto.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:web3kit/web3kit.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'; @@ -40,18 +39,24 @@ class YieldDto with _$YieldDto { required TokenDto token0, required TokenDto token1, required String poolAddress, + required String positionManagerAddress, required int tickSpacing, required ProtocolDto protocol, required int feeTier, - @JsonKey(name: "yield") required num yearlyYield, + required num yield24h, + required num yield30d, + required num yield90d, + required int chainId, @Default(0) num totalValueLockedUSD, - required Networks network, }) = _YieldDto; + AppNetworks get network => AppNetworks.fromChainId(chainId)!; + TokenDto maybeNativeToken0({required bool permitNative}) { - if (permitNative && token0.address.lowercasedEquals(network.wrappedNative.address)) { + if (permitNative && + (token0.addresses[network.chainId]!).lowercasedEquals(network.wrappedNative.addresses[network.chainId]!)) { return TokenDto( - address: EthereumConstants.zeroAddress, + addresses: {network.chainId: network.wrappedNative.addresses[network.chainId]!}, decimals: network.chainInfo.nativeCurrency!.decimals, logoUrl: network.chainInfo.nativeCurrency!.logoUrl, symbol: network.chainInfo.nativeCurrency!.symbol, @@ -63,9 +68,10 @@ class YieldDto with _$YieldDto { } TokenDto maybeNativeToken1({required bool permitNative}) { - if (permitNative && token1.address.lowercasedEquals(network.wrappedNative.address)) { + if (permitNative && + token1.addresses[network.chainId]!.lowercasedEquals(network.wrappedNative.addresses[network.chainId]!)) { return TokenDto( - address: EthereumConstants.zeroAddress, + addresses: {network.chainId: network.wrappedNative.addresses[network.chainId]!}, decimals: network.chainInfo.nativeCurrency!.decimals, logoUrl: network.chainInfo.nativeCurrency!.logoUrl, symbol: network.chainInfo.nativeCurrency!.symbol, @@ -76,31 +82,41 @@ class YieldDto with _$YieldDto { return token1; } - bool get isToken0WrappedNative => token0.address.lowercasedEquals(network.wrappedNativeTokenAddress); - bool get isToken1WrappedNative => token1.address.lowercasedEquals(network.wrappedNativeTokenAddress); + bool get isToken0WrappedNative => + token0.addresses[network.chainId]!.lowercasedEquals(network.wrappedNativeTokenAddress); + + bool get isToken1WrappedNative => + token1.addresses[network.chainId]!.lowercasedEquals(network.wrappedNativeTokenAddress); factory YieldDto.fromJson(Map json) => _$YieldDtoFromJson(json); factory YieldDto.fixture() => YieldDto( feeTier: 0, + yield24h: 32.2, + yield30d: 32.2, + yield90d: 32.2, + positionManagerAddress: "0x5Df2f0aFb5b5bB2Df9D1e9C7b6f5f0DD5f9eD5e0", poolAddress: "0x5Df2f0aFb5b5bB2Df9D1e9C7b6f5f0DD5f9eD5e0", token0: TokenDto.fixture().copyWith( symbol: "USDC", decimals: 6, - address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + 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: 18, - address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + addresses: { + AppNetworks.sepolia.chainId: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + }, logoUrl: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png", ), - yearlyYield: 5634.2, tickSpacing: 10, protocol: ProtocolDto.fixture(), - network: Networks.sepolia, + chainId: AppNetworks.sepolia.chainId, ); } diff --git a/lib/core/dtos/yields_by_timeframe_dto.dart b/lib/core/dtos/yields_by_timeframe_dto.dart deleted file mode 100644 index fdefe55..0000000 --- a/lib/core/dtos/yields_by_timeframe_dto.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:zup_app/core/dtos/yield_dto.dart'; - -part 'yields_by_timeframe_dto.freezed.dart'; -part 'yields_by_timeframe_dto.g.dart'; - -@freezed -class YieldsByTimeframeDto with _$YieldsByTimeframeDto { - @JsonSerializable(explicitToJson: true) - const factory YieldsByTimeframeDto({ - @JsonKey(name: "bestYield24hs") required List best24hYields, - @JsonKey(name: "bestYield7d") required List best7dYields, - @JsonKey(name: "bestYield30d") required List best30dYields, - @JsonKey(name: "bestYield90d") required List best90dYields, - }) = _YieldsByTimeframeDto; - - factory YieldsByTimeframeDto.fromJson(Map json) => _$YieldsByTimeframeDtoFromJson(json); - - factory YieldsByTimeframeDto.empty() => const YieldsByTimeframeDto( - best24hYields: [], - best7dYields: [], - best30dYields: [], - best90dYields: [], - ); - - factory YieldsByTimeframeDto.fixture() => YieldsByTimeframeDto( - best24hYields: [ - YieldDto.fixture(), - ], - best7dYields: [ - YieldDto.fixture(), - ], - best30dYields: [ - YieldDto.fixture(), - ], - best90dYields: [ - YieldDto.fixture(), - ], - ); -} diff --git a/lib/core/dtos/yields_dto.dart b/lib/core/dtos/yields_dto.dart index 776626b..291f72c 100644 --- a/lib/core/dtos/yields_dto.dart +++ b/lib/core/dtos/yields_dto.dart @@ -2,8 +2,6 @@ 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/dtos/yield_dto.dart'; -import 'package:zup_app/core/dtos/yields_by_timeframe_dto.dart'; -import 'package:zup_app/core/enums/networks.dart'; part 'yields_dto.freezed.dart'; part 'yields_dto.g.dart'; @@ -14,139 +12,57 @@ class YieldsDto with _$YieldsDto { @JsonSerializable(explicitToJson: true) const factory YieldsDto({ - @JsonKey(name: "bestYieldsByFrame") required YieldsByTimeframeDto timeframedYields, - @Default(0) @JsonKey(name: "minTvlUSD") num minLiquidityUSD, + @Default([]) @JsonKey(name: "pools") List pools, + @Default(0) @JsonKey(name: "minTvlUsd") num minLiquidityUSD, }) = _YieldsDto; - bool get isEmpty => - timeframedYields.best24hYields.isEmpty && - timeframedYields.best7dYields.isEmpty && - timeframedYields.best30dYields.isEmpty && - timeframedYields.best90dYields.isEmpty; + bool get isEmpty => pools.isEmpty; + + YieldDto get best24hYield => ([...pools]..sort((a, b) => b.yield24h.compareTo(a.yield24h))).first; + YieldDto get best30dYield => ([...pools]..sort((a, b) => b.yield30d.compareTo(a.yield30d))).first; + YieldDto get best90dYield => ([...pools]..sort((a, b) => b.yield90d.compareTo(a.yield90d))).first; factory YieldsDto.fromJson(Map json) => _$YieldsDtoFromJson(json); - factory YieldsDto.empty() => YieldsDto(timeframedYields: YieldsByTimeframeDto.empty()); + factory YieldsDto.empty() => const YieldsDto( + pools: [], + minLiquidityUSD: 0, + ); factory YieldsDto.fixture() => const YieldsDto( - timeframedYields: YieldsByTimeframeDto( - best24hYields: [ - YieldDto( - token0: TokenDto( - address: "0x02a3e7E0480B668bD46b42852C58363F93e3bA5C", - decimals: 6, - logoUrl: - "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/scroll/assets/0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4/logo.png", - name: "USDC", - symbol: "USDC", - ), - token1: TokenDto( - address: "0x5300000000000000000000000000000000000004", - decimals: 18, - logoUrl: - "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/scroll/assets/0x5300000000000000000000000000000000000004/logo.png", - name: "Wrapped Ether", - symbol: "WETH", - ), - network: Networks.sepolia, - poolAddress: "0x4040CE732c1A538A4Ac3157FDC35179D73ea76cd", - tickSpacing: 10, - yearlyYield: 1732.42, - feeTier: 500, - protocol: ProtocolDto( - name: "PancakeSwap", - logo: - "https://raw.githubusercontent.com/trustwallet/assets/master/dapps/exchange.pancakeswap.finance.png", - ), + pools: [ + YieldDto( + positionManagerAddress: "0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4", + token0: TokenDto( + addresses: {11155111: "0x02a3e7E0480B668bD46b42852C58363F93e3bA5C"}, + decimals: 6, + logoUrl: + "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/scroll/assets/0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4/logo.png", + name: "USDC", + symbol: "USDC", + ), + token1: TokenDto( + addresses: {11155111: "0x5300000000000000000000000000000000000004"}, + decimals: 18, + logoUrl: + "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/scroll/assets/0x5300000000000000000000000000000000000004/logo.png", + name: "Wrapped Ether", + symbol: "WETH", + ), + chainId: 11155111, + poolAddress: "0x4040CE732c1A538A4Ac3157FDC35179D73ea76cd", + tickSpacing: 10, + yield24h: 1732.42, + yield30d: 765.61, + yield90d: 2022.99, + totalValueLockedUSD: 65434567890.21, + feeTier: 500, + protocol: ProtocolDto( + name: "PancakeSwap", + logo: + "https://raw.githubusercontent.com/trustwallet/assets/master/dapps/exchange.pancakeswap.finance.png", ), - ], - best7dYields: [ - YieldDto( - token0: TokenDto( - address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", - decimals: 6, - name: "USDC", - symbol: "USDC", - logoUrl: - "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png", - ), - token1: TokenDto( - decimals: 18, - name: "Wrapped Ether", - symbol: "WETH", - address: "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", - logoUrl: - "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png", - ), - network: Networks.sepolia, - poolAddress: "0xFeEd501c2B21D315F04946F85fC6416B640240b5", - tickSpacing: 1, - feeTier: 100, - yearlyYield: 143.76, - protocol: ProtocolDto( - name: "Uniswap", - logo: "https://raw.githubusercontent.com/trustwallet/assets/master/dapps/app.uniswap.org.png", - ), - ) - ], - best30dYields: [ - YieldDto( - token0: TokenDto( - address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", - decimals: 6, - name: "USDC", - symbol: "USDC", - logoUrl: - "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png", - ), - token1: TokenDto( - decimals: 18, - name: "Wrapped Ether", - symbol: "WETH", - address: "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", - logoUrl: - "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png", - ), - network: Networks.sepolia, - poolAddress: "0xFeEd501c2B21D315F04946F85fC6416B640240b5", - tickSpacing: 1, - feeTier: 100, - yearlyYield: 143.76, - protocol: ProtocolDto( - name: "Uniswap", - logo: "https://raw.githubusercontent.com/trustwallet/assets/master/dapps/app.uniswap.org.png", - ), - ) - ], - best90dYields: [ - YieldDto( - feeTier: 100, - token0: TokenDto( - address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", - decimals: 6, - name: "USDC", - symbol: "USDC", - logoUrl: - "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png", - ), - token1: TokenDto( - decimals: 18, - name: "Wrapped Ether", - symbol: "WETH", - address: "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", - logoUrl: - "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png", - ), - network: Networks.sepolia, - poolAddress: "0xFeEd501c2B21D315F04946F85fC6416B640240b5", - protocol: ProtocolDto( - name: "Uniswap", - logo: "https://raw.githubusercontent.com/trustwallet/assets/master/dapps/app.uniswap.org.png", - ), - tickSpacing: 1, - yearlyYield: 21.4, - ) - ], - ), + ), + ], ); } diff --git a/lib/core/enums/networks.dart b/lib/core/enums/networks.dart index e1bebf3..d68d8e1 100644 --- a/lib/core/enums/networks.dart +++ b/lib/core/enums/networks.dart @@ -5,34 +5,62 @@ import 'package:web3kit/web3kit.dart'; import 'package:zup_app/core/dtos/token_dto.dart'; import 'package:zup_app/gen/assets.gen.dart'; -enum Networks { +enum AppNetworks { + allNetworks, mainnet, scroll, sepolia; - static List get testnets => Networks.values.where((network) => network.isTestnet).toList(); - static List get mainnets => Networks.values.where((network) => !network.isTestnet).toList(); - static Networks? fromValue(String value) => Networks.values.firstWhereOrNull((network) => network.name == value); + static List get testnets => AppNetworks.values + .where( + (network) => !network.isAllNetworks && network.isTestnet, + ) + .toList(); + + static List get mainnets => AppNetworks.values + .where( + (network) => network.isAllNetworks || !network.isTestnet, + ) + .toList(); + + static AppNetworks? fromValue(String value) => + AppNetworks.values.firstWhereOrNull((network) => network.name == value); + + static AppNetworks? fromChainId(int chainId) => AppNetworks.values.firstWhereOrNull( + (network) { + if (network.isAllNetworks) return false; + + return int.parse(network.chainInfo.hexChainId) == chainId; + }, + ); + + int get chainId => int.parse(chainInfo.hexChainId); + + bool get isAllNetworks => this == allNetworks; bool get isTestnet => switch (this) { mainnet => false, scroll => false, sepolia => true, + allNetworks => false, }; String get label => switch (this) { sepolia => "Sepolia", mainnet => "Ethereum", scroll => "Scroll", + allNetworks => "All Networks", }; Widget get icon => switch (this) { sepolia => Assets.logos.ethereum.svg(), mainnet => Assets.logos.ethereum.svg(), scroll => Assets.logos.scroll.svg(), + allNetworks => Assets.icons.all.svg(), }; ChainInfo get chainInfo => switch (this) { + allNetworks => throw UnimplementedError("allNetworks is not a valid network"), sepolia => ChainInfo( hexChainId: "0xaa36a7", chainName: label, @@ -57,28 +85,30 @@ enum Networks { }; String get wrappedNativeTokenAddress => switch (this) { + allNetworks => throw UnimplementedError("allNetworks is not a valid network"), sepolia => "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", mainnet => "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", scroll => "0x5300000000000000000000000000000000000004", }; TokenDto get wrappedNative => switch (this) { + allNetworks => throw UnimplementedError("allNetworks is not a valid network"), sepolia => TokenDto( - address: wrappedNativeTokenAddress, + addresses: {chainId: wrappedNativeTokenAddress}, name: "Wrapped Ether", decimals: NativeCurrencies.eth.currencyInfo.decimals, symbol: "WETH", logoUrl: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/info/logo.png", ), mainnet => TokenDto( - address: wrappedNativeTokenAddress, + addresses: {chainId: wrappedNativeTokenAddress}, decimals: NativeCurrencies.eth.currencyInfo.decimals, name: "Wrapped Ether", symbol: "WETH", logoUrl: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/info/logo.png", ), scroll => TokenDto( - address: wrappedNativeTokenAddress, + addresses: {chainId: wrappedNativeTokenAddress}, decimals: NativeCurrencies.eth.currencyInfo.decimals, name: "Wrapped Ether", symbol: "WETH", @@ -88,28 +118,27 @@ enum Networks { }; String get rpcUrl => switch (this) { + allNetworks => throw UnimplementedError("allNetworks is not a valid network"), sepolia => "https://ethereum-sepolia-rpc.publicnode.com", mainnet => "https://ethereum-rpc.publicnode.com", scroll => "https://scroll-rpc.publicnode.com", }; TokenDto get nativeCurrencyTokenDto => switch (this) { + allNetworks => throw UnimplementedError("allNetworks is not a valid network"), sepolia => TokenDto( - address: EthereumConstants.zeroAddress, name: NativeCurrencies.eth.currencyInfo.name, decimals: NativeCurrencies.eth.currencyInfo.decimals, symbol: NativeCurrencies.eth.currencyInfo.symbol, logoUrl: NativeCurrencies.eth.currencyInfo.logoUrl, ), mainnet => TokenDto( - address: EthereumConstants.zeroAddress, name: NativeCurrencies.eth.currencyInfo.name, decimals: NativeCurrencies.eth.currencyInfo.decimals, symbol: NativeCurrencies.eth.currencyInfo.symbol, logoUrl: NativeCurrencies.eth.currencyInfo.logoUrl, ), scroll => TokenDto( - address: EthereumConstants.zeroAddress, name: NativeCurrencies.eth.currencyInfo.name, decimals: NativeCurrencies.eth.currencyInfo.decimals, symbol: NativeCurrencies.eth.currencyInfo.symbol, diff --git a/lib/core/mixins/keys_mixin.dart b/lib/core/mixins/keys_mixin.dart index ed0a12d..cc96ec1 100644 --- a/lib/core/mixins/keys_mixin.dart +++ b/lib/core/mixins/keys_mixin.dart @@ -1,11 +1,11 @@ import 'package:zup_app/core/enums/networks.dart'; mixin KeysMixin { - String userTokenBalanceCacheKey({required String userAddress, required String tokenAddress}) { - return 'userTokenBalance-$userAddress-$tokenAddress'; + String userTokenBalanceCacheKey({required String userAddress, required String tokenAddress, bool isNative = false}) { + return 'userTokenBalance-$userAddress-$tokenAddress-native=$isNative'; } - String poolTickCacheKey({required Networks network, required String poolAddress}) { + String poolTickCacheKey({required AppNetworks network, required String poolAddress}) { return 'poolTick-$poolAddress-${network.name}'; } } diff --git a/lib/core/repositories/tokens_repository.dart b/lib/core/repositories/tokens_repository.dart index 2d15c67..c9c119c 100644 --- a/lib/core/repositories/tokens_repository.dart +++ b/lib/core/repositories/tokens_repository.dart @@ -1,6 +1,5 @@ import 'package:dio/dio.dart'; import 'package:zup_app/core/dtos/token_dto.dart'; -import 'package:zup_app/core/dtos/token_list_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; class TokensRepository { @@ -10,19 +9,18 @@ class TokensRepository { bool isSearchingTokens = false; CancelToken? _searchTokenLastCancelToken; - Future getTokenList(Networks network, {String? userAddress}) async { + Future> getPopularTokens(AppNetworks network) async { final request = await _zupAPIDio.get( - "/tokens", + "/tokens/popular", queryParameters: { - "network": network.name, - if (userAddress != null) "userAddress": userAddress, + if (!network.isAllNetworks) "chainId": int.parse(network.chainInfo.hexChainId), }, ); - return TokenListDto.fromJson(request.data); + return request.data.map((token) => TokenDto.fromJson(token)).toList(); } - Future> searchToken(String query, Networks network) async { + Future> searchToken(String query, AppNetworks network) async { if (_searchTokenLastCancelToken != null) { _searchTokenLastCancelToken!.cancel(); } @@ -30,7 +28,7 @@ class TokensRepository { _searchTokenLastCancelToken = CancelToken(); final response = await _zupAPIDio.get("/tokens/search", cancelToken: _searchTokenLastCancelToken, queryParameters: { - "network": network.name, + if (!network.isAllNetworks) "chainId": network.chainId, "query": query, }); diff --git a/lib/core/repositories/yield_repository.dart b/lib/core/repositories/yield_repository.dart index 7396572..b856ebc 100644 --- a/lib/core/repositories/yield_repository.dart +++ b/lib/core/repositories/yield_repository.dart @@ -8,19 +8,37 @@ class YieldRepository { final Dio _zupAPIDio; - Future getYields({ + Future getSingleNetworkYield({ required String token0Address, required String token1Address, - required Networks network, - required num minTvlUsd, + required AppNetworks network, + num? minTvlUsd, }) async { - final response = await _zupAPIDio.get("/pools", queryParameters: { - "token0": token0Address != EthereumConstants.zeroAddress ? token0Address : network.wrappedNative.address, - "token1": token1Address != EthereumConstants.zeroAddress ? token1Address : network.wrappedNative.address, - "network": network.name, - "minTvlUsd": minTvlUsd + final response = await _zupAPIDio.get("/pools/search/${network.chainId}", queryParameters: { + "token0Address": token0Address != EthereumConstants.zeroAddress + ? token0Address + : network.wrappedNative.addresses[network.chainId]!, + "token1Address": token1Address != EthereumConstants.zeroAddress + ? token1Address + : network.wrappedNative.addresses[network.chainId]!, + if (minTvlUsd != null) "minTvlUsd": minTvlUsd }); - return YieldsDto.fromJson(response.data["bestYields"]); + return YieldsDto.fromJson(response.data); + } + + Future getAllNetworksYield( + {required String token0InternalId, + required String token1InternalId, + num? minTvlUsd, + bool testnetMode = false}) async { + final response = await _zupAPIDio.get("/pools/search/all", queryParameters: { + "token0Id": token0InternalId, + "token1Id": token1InternalId, + "testnetMode": testnetMode, + if (minTvlUsd != null) "minTvlUsd": minTvlUsd, + }); + + return YieldsDto.fromJson(response.data); } } diff --git a/lib/core/zup_analytics.dart b/lib/core/zup_analytics.dart index 986937e..0260a5b 100644 --- a/lib/core/zup_analytics.dart +++ b/lib/core/zup_analytics.dart @@ -33,8 +33,8 @@ class ZupAnalytics { await _log( "user_deposited", { - "token0_address": "hex:${depositedYield.token0.address}", - "token1_address": "hex:${depositedYield.token1.address}", + "token0_address": "hex:${depositedYield.token0.addresses[depositedYield.network.chainId]!}", + "token1_address": "hex:${depositedYield.token1.addresses[depositedYield.network.chainId]!}", "amount0": amount0, "amount1": amount1, "network": depositedYield.network.label, diff --git a/lib/core/zup_navigator.dart b/lib/core/zup_navigator.dart index 82bba08..ec2b1b2 100644 --- a/lib/core/zup_navigator.dart +++ b/lib/core/zup_navigator.dart @@ -13,7 +13,7 @@ class ZupNavigator { Future navigateToNewPosition() async => await Routefly.navigate(ZupNavigatorPaths.newPosition.path); - Future navigateToDeposit(String token0, String token1, Networks network) async { + Future navigateToDeposit(String token0, String token1, AppNetworks network) async { const depositPath = ZupNavigatorPaths.deposit; await Routefly.pushNavigate( diff --git a/lib/l10n/en.arb b/lib/l10n/en.arb index 65b8508..fae6f3d 100644 --- a/lib/l10n/en.arb +++ b/lib/l10n/en.arb @@ -1,5 +1,13 @@ { "@@locale": "en", + "yieldCardNetworkTooltipDescription": "This pool is at {network}", + "@yieldCardNetworkTooltipDescription": { + "placeholders": { + "network": { + "type": "String" + } + } + }, "twentyFourHours": "24h", "appFooterTermsOfUse": "Terms of Use", "privacyPolicy": "Privacy Policy", @@ -207,6 +215,8 @@ "tokenSelectorModalTitle": "Select a token", "tokenSelectorModalDescription": "Pick a token from our list or search by symbol or address to build your ideal liquidity pool!", "tokenSelectorModalSearchTitle": "Search token or paste address", + "tokenSelectorModalSearchTitleAllNetworks": "Search token by symbol or name", + "tokenSelectorModalSearchAlertForAllNetworks": "When ‘All Networks’ is selected, you can only search by name or symbol. To search by address as well, please select a specific network", "tokenSelectorModalErrorDescription": "We hit a snag loading your token list. Give it another go, and if it keeps happening, feel free to reach us", "tokenSelectorModalSearchErrorDescription": "We hit a snag while searching for a token matching {searchedTerm}. Give it another go, and if it keeps happening, feel free to reach us", "noResultsFor": "No results for", diff --git a/lib/l10n/gen/app_localizations.dart b/lib/l10n/gen/app_localizations.dart index 2479cca..7186596 100644 --- a/lib/l10n/gen/app_localizations.dart +++ b/lib/l10n/gen/app_localizations.dart @@ -93,6 +93,12 @@ abstract class S { /// A list of this localizations delegate's supported locales. static const List supportedLocales = [Locale('en')]; + /// No description provided for @yieldCardNetworkTooltipDescription. + /// + /// In en, this message translates to: + /// **'This pool is at {network}'** + String yieldCardNetworkTooltipDescription({required String network}); + /// No description provided for @twentyFourHours. /// /// In en, this message translates to: @@ -658,6 +664,18 @@ abstract class S { /// **'Search token or paste address'** String get tokenSelectorModalSearchTitle; + /// No description provided for @tokenSelectorModalSearchTitleAllNetworks. + /// + /// In en, this message translates to: + /// **'Search token by symbol or name'** + String get tokenSelectorModalSearchTitleAllNetworks; + + /// No description provided for @tokenSelectorModalSearchAlertForAllNetworks. + /// + /// In en, this message translates to: + /// **'When ‘All Networks’ is selected, you can only search by name or symbol. To search by address as well, please select a specific network'** + String get tokenSelectorModalSearchAlertForAllNetworks; + /// No description provided for @tokenSelectorModalErrorDescription. /// /// 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 0a15544..1a6d63f 100644 --- a/lib/l10n/gen/app_localizations_en.dart +++ b/lib/l10n/gen/app_localizations_en.dart @@ -8,6 +8,11 @@ import 'app_localizations.dart'; class SEn extends S { SEn([String locale = 'en']) : super(locale); + @override + String yieldCardNetworkTooltipDescription({required String network}) { + return 'This pool is at $network'; + } + @override String get twentyFourHours => '24h'; @@ -348,6 +353,14 @@ class SEn extends S { @override String get tokenSelectorModalSearchTitle => 'Search token or paste address'; + @override + String get tokenSelectorModalSearchTitleAllNetworks => + 'Search token by symbol or name'; + + @override + String get tokenSelectorModalSearchAlertForAllNetworks => + 'When ‘All Networks’ is selected, you can only search by name or symbol. To search by address as well, please select a specific network'; + @override String get tokenSelectorModalErrorDescription => 'We hit a snag loading your token list. Give it another go, and if it keeps happening, feel free to reach us'; diff --git a/lib/widgets/app_header/app_header.dart b/lib/widgets/app_header/app_header.dart index a975129..c1b5946 100644 --- a/lib/widgets/app_header/app_header.dart +++ b/lib/widgets/app_header/app_header.dart @@ -28,8 +28,8 @@ class _AppHeaderState extends State with DeviceInfoMixin { final ZupNavigator navigator = inject(); final appCubit = inject(); - List get currentModeNetworks { - return appCubit.isTestnetMode ? Networks.testnets : Networks.mainnets; + List get currentModeNetworks { + return appCubit.isTestnetMode ? AppNetworks.testnets : AppNetworks.mainnets; } Function() onRouteChange = () {}; @@ -128,7 +128,8 @@ class _AppHeaderState extends State with DeviceInfoMixin { (index) => NetworkSwitcherItem( title: currentModeNetworks[index].label, icon: currentModeNetworks[index].icon, - chainInfo: currentModeNetworks[index].chainInfo, + chainInfo: + currentModeNetworks[index].isAllNetworks ? null : currentModeNetworks[index].chainInfo, ), ), ), diff --git a/lib/widgets/token_selector_modal/token_selector_modal.dart b/lib/widgets/token_selector_modal/token_selector_modal.dart index bd28772..6b0456d 100644 --- a/lib/widgets/token_selector_modal/token_selector_modal.dart +++ b/lib/widgets/token_selector_modal/token_selector_modal.dart @@ -1,5 +1,6 @@ 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/injections.dart'; @@ -7,7 +8,6 @@ import 'package:zup_app/gen/assets.gen.dart'; import 'package:zup_app/l10n/gen/app_localizations.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_app/widgets/zup_skeletonizer.dart'; import 'package:zup_core/mixins/device_info_mixin.dart'; import 'package:zup_ui_kit/zup_ui_kit.dart'; @@ -44,9 +44,9 @@ class _TokenSelectorModalState extends State with DeviceInfo final double _horizontalPadding = 20; final EdgeInsetsGeometry _paddingBetweenListItems = const EdgeInsets.symmetric(vertical: 5); - final _zupCachedImage = inject(); final _debouncer = inject(); final _cubit = inject(); + final _appCubit = inject(); void _selectToken(TokenDto token) { widget.onSelectToken(token); @@ -88,20 +88,34 @@ class _TokenSelectorModalState extends State with DeviceInfo backgroundColor: Colors.white, surfaceTintColor: Colors.white, titleSpacing: 20, - toolbarHeight: 60, + toolbarHeight: _appCubit.selectedNetwork.isAllNetworks ? 100 : 60, automaticallyImplyLeading: false, leadingWidth: 0, floating: true, snap: true, - title: ZupTextField( - key: const Key("search-token-field"), - hintText: S.of(context).tokenSelectorModalSearchTitle, - onChanged: (query) { - _debouncer.run(() async { - if (query.isEmpty) return _cubit.fetchTokenList(); - _cubit.searchToken(query); - }); - }, + title: Column( + children: [ + ZupTextField( + key: const Key("search-token-field"), + hintText: _appCubit.selectedNetwork.isAllNetworks + ? S.of(context).tokenSelectorModalSearchTitleAllNetworks + : S.of(context).tokenSelectorModalSearchTitle, + onChanged: (query) { + _debouncer.run(() async { + if (query.isEmpty) return _cubit.fetchTokenList(); + _cubit.searchToken(query); + }); + }, + ), + if (_appCubit.selectedNetwork.isAllNetworks) ...[ + const SizedBox(height: 8), + Text( + maxLines: 4, + S.of(context).tokenSelectorModalSearchAlertForAllNetworks, + style: const TextStyle(color: ZupColors.gray, fontSize: 12), + ) + ] + ], ), ), ...state.maybeWhen( @@ -224,115 +238,29 @@ class _TokenSelectorModalState extends State with DeviceInfo ]; List _buildSuccessOrLoadingSlivers(TokenSelectorModalState state) => [ - ZupSkeletonizer( - enabled: state.maybeWhen(orElse: () => false, loading: () => true), - child: SliverToBoxAdapter( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: _horizontalPadding).copyWith(top: 10), - child: Wrap( - spacing: 10, - runSpacing: 10, - children: state.maybeWhen( - orElse: () => const [], - loading: () => [ - ZupMiniButton(title: "loading", onPressed: () {}), - ZupMiniButton(title: "loading", onPressed: () {}), - ZupMiniButton(title: "loading", onPressed: () {}), - ZupMiniButton(title: "loading", onPressed: () {}), - ZupMiniButton(title: "loading", onPressed: () {}), - ], - success: (tokenList) => List.generate( - tokenList.mostUsedTokens.length, - (index) { - final mostUsedToken = tokenList.mostUsedTokens[index]; - - return ZupMiniButton( - key: Key("most-used-token-$index"), - iconSize: 18, - onPressed: () => _selectToken(mostUsedToken), - title: mostUsedToken.symbol, - icon: _zupCachedImage.build(mostUsedToken.logoUrl, radius: 50), - ); - }, - ).toList(), - ), - ), - ), - ), - ).sliver(), - ZupSkeletonizer( - enabled: state.maybeWhen(orElse: () => false, loading: () => true), - child: state.maybeWhen( - orElse: () => const SliverToBoxAdapter(), - loading: () => _buildSliverSectionTitle("Loading..."), - success: (tokenList) { - return tokenList.userTokens.isEmpty - ? const SliverToBoxAdapter() - : SliverToBoxAdapter( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - _buildSectionTitle("My Tokens", topPadding: 0), - const Spacer(), - ZupRefreshButton( - key: const Key("refresh-token-list"), - size: 20, - onPressed: () async { - await Future.delayed(const Duration(milliseconds: 500)); - await _cubit.fetchTokenList(forceRefresh: true); - }), - SizedBox( - width: _horizontalPadding, - ) - ], - ), - ); - }, - ), - ).sliver(), - ZupSkeletonizer( - enabled: state.maybeWhen(orElse: () => false, loading: () => true), - child: SliverPadding( - padding: EdgeInsets.symmetric(horizontal: _horizontalPadding), - sliver: state.whenOrNull( - loading: () => SliverList( - delegate: SliverChildListDelegate( - List.generate( - 3, - (index) => Padding( - padding: _paddingBetweenListItems, - child: TokenCard(asset: TokenDto.fixture(), onClick: () {}), - ), - ), - )), - success: (tokenList) => SliverList.builder( - itemCount: tokenList.userTokens.length, - itemBuilder: (context, index) { - final userToken = tokenList.userTokens[index]; - - return Padding( - padding: _paddingBetweenListItems, - child: TokenCard( - key: Key("user-token-$index"), - asset: userToken, - onClick: () => _selectToken(userToken), - ), - ); - }, - ), - )), - ).sliver(), state.maybeWhen( - success: (tokenList) => _buildSliverSectionTitle(S.of(context).popularTokens), + success: (popularTokens) => _buildSliverSectionTitle(S.of(context).popularTokens), orElse: () => const SliverToBoxAdapter(), ), SliverPadding( padding: const EdgeInsets.symmetric(horizontal: 20).copyWith(bottom: 20), sliver: state.whenOrNull( - success: (tokenList) => SliverList.builder( - itemCount: tokenList.popularTokens.length, + loading: () => ZupSkeletonizer( + child: SliverList( + delegate: SliverChildListDelegate( + List.generate( + 4, + (index) => Padding( + padding: _paddingBetweenListItems, + child: TokenCard(asset: TokenDto.fixture(), onClick: () {}), + ), + ), + )), + ).sliver(), + success: (popularTokens) => SliverList.builder( + itemCount: popularTokens.length, itemBuilder: (context, index) { - final popularToken = tokenList.popularTokens[index]; + final popularToken = popularTokens[index]; return Padding( padding: _paddingBetweenListItems, 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 f65e6b3..694bfbc 100644 --- a/lib/widgets/token_selector_modal/token_selector_modal_cubit.dart +++ b/lib/widgets/token_selector_modal/token_selector_modal_cubit.dart @@ -4,7 +4,6 @@ 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/token_list_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/repositories/tokens_repository.dart'; @@ -19,8 +18,8 @@ class TokenSelectorModalCubit extends Cubit { final AppCubit _appCubit; final Wallet _wallet; - final Map> _tokenListCachedPerNetworkByAddress = {}; - Future get tokenList async => _tokenListCachedPerNetworkByAddress[_appCubit.selectedNetwork] + final Map>> _tokenListCachedPerNetworkByAddress = {}; + Future?> get tokenList async => _tokenListCachedPerNetworkByAddress[_appCubit.selectedNetwork] ?[await _wallet.signer?.address ?? EthereumConstants.zeroAddress]; Future _emitSuccessCached() async => emit(TokenSelectorModalState.success((await tokenList)!)); @@ -42,10 +41,7 @@ class TokenSelectorModalCubit extends Cubit { emit(const TokenSelectorModalState.loading()); _tokenListCachedPerNetworkByAddress[_appCubit.selectedNetwork]![userAddress] = - await _tokensRepository.getTokenList( - _appCubit.selectedNetwork, - userAddress: await _wallet.signer?.address, - ); + await _tokensRepository.getPopularTokens(_appCubit.selectedNetwork); if (_shouldDiscardTokenListLoadedState) return; @@ -58,9 +54,14 @@ class TokenSelectorModalCubit extends Cubit { } Future searchToken(String query) async { + if (query.isEthereumAddress() && _appCubit.selectedNetwork.isAllNetworks) { + return emit(TokenSelectorModalState.searchNotFound(query)); + } + try { emit(const TokenSelectorModalState.searchLoading()); final tokensList = await _tokensRepository.searchToken(query, _appCubit.selectedNetwork); + tokensList.removeWhere((token) => token.name.isEmpty && token.symbol.isEmpty); if (_shouldDiscardSearchState) return; 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 b0b427f..659ae76 100644 --- a/lib/widgets/token_selector_modal/token_selector_modal_state.dart +++ b/lib/widgets/token_selector_modal/token_selector_modal_state.dart @@ -5,7 +5,7 @@ class TokenSelectorModalState with _$TokenSelectorModalState { const factory TokenSelectorModalState.initial() = _Initial; const factory TokenSelectorModalState.loading() = _Loading; const factory TokenSelectorModalState.searchLoading() = _SearchLoading; - const factory TokenSelectorModalState.success(TokenListDto tokenList) = _Success; + const factory TokenSelectorModalState.success(List popularTokens) = _Success; const factory TokenSelectorModalState.searchSuccess(List result) = _SearchSuccess; const factory TokenSelectorModalState.error() = _Error; const factory TokenSelectorModalState.searchError(String searchedTerm) = _SearchError; diff --git a/lib/widgets/yield_card.dart b/lib/widgets/yield_card.dart index 7b607a3..5f24052 100644 --- a/lib/widgets/yield_card.dart +++ b/lib/widgets/yield_card.dart @@ -11,13 +11,13 @@ import 'package:zup_ui_kit/zup_ui_kit.dart'; class YieldCard extends StatefulWidget { const YieldCard({ super.key, - required this.yield, + required this.currentYield, required this.onChangeSelection, required this.isSelected, required this.timeFrame, }); - final YieldDto yield; + final YieldDto currentYield; final bool isSelected; final Function(YieldDto? yield) onChangeSelection; final YieldTimeFrame timeFrame; @@ -32,6 +32,18 @@ class _YieldCardState extends State { final selectionAnimationDuration = const Duration(milliseconds: 150); + String get yieldTimeFramed { + if (widget.timeFrame.isDay) { + return widget.currentYield.yield24h.formatPercent; + } + + if (widget.timeFrame.isMonth) { + return widget.currentYield.yield30d.formatPercent; + } + + return widget.currentYield.yield90d.formatPercent; + } + @override Widget build(BuildContext context) { return Column( @@ -48,29 +60,61 @@ class _YieldCardState extends State { ZupSelectableCard( isSelected: widget.isSelected, selectionAnimationDuration: selectionAnimationDuration, - onPressed: () => widget.onChangeSelection(widget.isSelected ? null : widget.yield), + onPressed: () => widget.onChangeSelection(widget.isSelected ? null : widget.currentYield), padding: const EdgeInsets.all(10).copyWith(right: 0, top: 0), width: double.maxFinite, child: Stack( children: [ + if (appCubit.selectedNetwork.isAllNetworks) + Positioned( + right: 2, + top: 2, + child: ZupTooltip( + message: S.of(context).yieldCardThisPoolIsAtNetwork(network: widget.currentYield.network.label), + trailingIcon: widget.currentYield.network.icon, + child: AnimatedContainer( + duration: selectionAnimationDuration, + height: 40, + padding: const EdgeInsets.all(6), + width: 40, + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + blurStyle: BlurStyle.inner, + color: widget.isSelected ? ZupColors.brand5 : ZupColors.gray5, + blurRadius: 2, + spreadRadius: -2, + offset: const Offset(0, 0), + ), + BoxShadow( + color: widget.isSelected ? ZupColors.brand7 : ZupColors.white, + blurRadius: 5, + spreadRadius: -1, + offset: const Offset(2, -2), + ), + ], + borderRadius: BorderRadius.circular(8), + ), + child: widget.currentYield.network.icon, + ), + ), + ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(top: 10), child: Text( - widget.timeFrame.isDay - ? S.of(context).yieldCardYieldYearly - : S.of(context).yieldCardAverageYieldYearly, + S.of(context).yieldCardYieldYearly, style: const TextStyle(fontSize: 14), ), ), Text( - widget.yield.yearlyYield.formatPercent, + yieldTimeFramed, style: const TextStyle(fontSize: 26, fontWeight: FontWeight.w600), ), Text( - "${NumberFormat.compactSimpleCurrency(decimalDigits: 2).format(widget.yield.totalValueLockedUSD)} ${S.of(context).tvl}", + "${NumberFormat.compactSimpleCurrency(decimalDigits: 2).format(widget.currentYield.totalValueLockedUSD)} ${S.of(context).tvl}", style: const TextStyle( fontSize: 14, height: 1, @@ -81,16 +125,16 @@ class _YieldCardState extends State { Row( mainAxisSize: MainAxisSize.min, children: [ - if (widget.yield.protocol.logo.isNotEmpty) + if (widget.currentYield.protocol.logo.isNotEmpty) zupCachedImage.build( - widget.yield.protocol.logo, + widget.currentYield.protocol.logo, height: 25, width: 25, radius: 50, ), const SizedBox(width: 5), Text( - widget.yield.protocol.name, + widget.currentYield.protocol.name, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600), ), ], diff --git a/pubspec.lock b/pubspec.lock index 9c86dfb..38677b1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1261,7 +1261,7 @@ packages: description: path: "." ref: main - resolved-ref: "3157929242110d0f12644d5bc4afa8a6cd181eab" + resolved-ref: efecab377221d2984aaaa7329dfb5cebcccf58f2 url: "https://github.com/Zup-Protocol/web3kit.git" source: git version: "0.0.1" @@ -1319,7 +1319,7 @@ packages: description: path: "." ref: main - resolved-ref: "075dd0601cfbd4304ad52476fd77f47724daa989" + resolved-ref: e67c82ded372f740d5b2e7823d4bce070efdb3bb 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 757ca03..e6c1770 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,17 +21,14 @@ dependencies: sdk: flutter get_it: ^7.7.0 web3kit: - # path: ../web3kit git: url: https://github.com/Zup-Protocol/web3kit.git ref: main zup_ui_kit: - # path: ../zup_ui_kit git: url: https://github.com/Zup-Protocol/zup-ui-kit.git ref: main zup_core: - # path: ../zup_core git: url: https://github.com/Zup-Protocol/zup-core.git ref: main @@ -56,6 +53,14 @@ dependencies: firebase_analytics: ^11.4.5 envied: ^1.1.1 +dependency_overrides: + # zup_core: + # path: ../zup-core + # web3kit: + # path: ../web3kit + # zup_ui_kit: + # path: ../zup-ui-kit + dev_dependencies: flutter_test: sdk: flutter diff --git a/test/app/app_cubit_test.dart b/test/app/app_cubit_test.dart index 70acaa9..69b2db5 100644 --- a/test/app/app_cubit_test.dart +++ b/test/app/app_cubit_test.dart @@ -29,7 +29,7 @@ void main() { test("When calling the `selectedNetwork` after initializing the cubit, it should return the initial selected network", () { - expect(sut.selectedNetwork, Networks.mainnet); + expect(sut.selectedNetwork, AppNetworks.allNetworks); }); test("""When an event is emitted that the signer changed, @@ -45,7 +45,7 @@ void main() { when(() => wallet0.connectedNetwork).thenAnswer((_) async => const ChainInfo(hexChainId: signerNetwork)); when(() => wallet0.switchOrAddNetwork(any())).thenAnswer((_) async {}); - final sut0 = AppCubit(wallet0, cache)..updateAppNetwork(Networks.sepolia); + final sut0 = AppCubit(wallet0, cache)..updateAppNetwork(AppNetworks.sepolia); signerStreamController.add(signer); @@ -72,13 +72,13 @@ void main() { final signerStreamController = StreamController.broadcast(); final signerStream = signerStreamController.stream; final signer = SignerMock(); - final signerNetwork = Networks.sepolia.chainInfo.hexChainId; + final signerNetwork = AppNetworks.sepolia.chainInfo.hexChainId; when(() => wallet0.signerStream).thenAnswer((_) => signerStream); when(() => wallet0.connectedNetwork).thenAnswer((_) async => ChainInfo(hexChainId: signerNetwork)); when(() => wallet0.switchOrAddNetwork(any())).thenAnswer((_) async {}); - AppCubit(wallet0, cache).updateAppNetwork(Networks.sepolia); + AppCubit(wallet0, cache).updateAppNetwork(AppNetworks.sepolia); signerStreamController.add(signer); @@ -97,7 +97,7 @@ void main() { when(() => wallet0.connectedNetwork).thenAnswer((_) async => const ChainInfo(hexChainId: "")); when(() => wallet0.switchOrAddNetwork(any())).thenAnswer((_) async {}); - AppCubit(wallet0, cache).updateAppNetwork(Networks.sepolia); + AppCubit(wallet0, cache).updateAppNetwork(AppNetworks.sepolia); signerStreamController.add(null); @@ -107,14 +107,14 @@ void main() { }); test("When calling `updateAppNetwork` it should update the selected network variable", () async { - sut.updateAppNetwork(Networks.sepolia); + sut.updateAppNetwork(AppNetworks.sepolia); - expect(sut.selectedNetwork, Networks.sepolia); + expect(sut.selectedNetwork, AppNetworks.sepolia); }); test("""When calling `updateAppNetwork` it should emit the state `networkChanged` with the new network but it should finish with the event `standard` """, () async { - const network = Networks.sepolia; + const network = AppNetworks.sepolia; expectLater(sut.stream, emitsInOrder([const AppState.networkChanged(network), const AppState.standard()])); @@ -124,7 +124,7 @@ void main() { }); test("When changing the network, it should add an event to the network stream", () { - const network = Networks.sepolia; + const network = AppNetworks.sepolia; expectLater(sut.selectedNetworkStream, emits(network)); @@ -149,7 +149,7 @@ void main() { when(() => cache.getTestnetMode()).thenReturn(true); final sut0 = AppCubit(wallet, cache); - expect(sut0.selectedNetwork, Networks.sepolia); + expect(sut0.selectedNetwork, AppNetworks.sepolia); }); test("If the cached testnet mode is true when initializing the cubit, the state testnetModeChanged should be emitted", @@ -172,17 +172,17 @@ void main() { expectLater( sut.stream, emitsInOrder( - [const AppState.networkChanged(Networks.sepolia), const AppState.standard()], + [const AppState.networkChanged(AppNetworks.sepolia), const AppState.standard()], ), ); await sut.toggleTestnetMode(); // assuming it starts by default as false - expect(sut.selectedNetwork, Networks.sepolia); + expect(sut.selectedNetwork, AppNetworks.sepolia); }); - test("""When calling `toggleTestnetMode` for true it should emit a `networkChanged` - for the mainnet network and update the selected network variable""", () async { + test("""When calling `toggleTestnetMode` for false it should emit a `networkChanged` + for a mainnet network and update the selected network variable""", () async { when(() => cache.getTestnetMode()).thenReturn(true); final sut0 = AppCubit(wallet, cache); @@ -190,13 +190,13 @@ void main() { expectLater( sut0.stream, emitsInOrder( - [const AppState.networkChanged(Networks.mainnet), const AppState.standard()], + [const AppState.networkChanged(AppNetworks.allNetworks), const AppState.standard()], ), ); await sut0.toggleTestnetMode(); - expect(sut0.selectedNetwork, Networks.mainnet); + expect(sut0.selectedNetwork, AppNetworks.allNetworks); }); test("When calling `toggleTestnetMode` it should save the `isTestnetMode` variable in the cache after toggling", @@ -218,23 +218,7 @@ void main() { await sut.toggleTestnetMode(); // assuming it starts by default as false - verify(() => wallet.switchOrAddNetwork(Networks.sepolia.chainInfo)).called(1); - }); - - test("""When calling `toggleTestnetMode` for true and there is a signer with a different connected - network, it should try to switch the wallet network for the default mainnet network""", () async { - final signer = SignerMock(); - - when(() => cache.getTestnetMode()).thenReturn(true); - when(() => wallet.signer).thenReturn(signer); - when(() => wallet.connectedNetwork).thenAnswer((_) async => const ChainInfo( - hexChainId: "0x32", - )); - - final sut0 = AppCubit(wallet, cache); - await sut0.toggleTestnetMode(); - - verify(() => wallet.switchOrAddNetwork(Networks.mainnet.chainInfo)).called(1); + verify(() => wallet.switchOrAddNetwork(AppNetworks.sepolia.chainInfo)).called(1); }); test( @@ -267,4 +251,10 @@ void main() { await sut0.toggleTestnetMode(); }); + + test("When calling `currentChainId` it should get exactly the chain id of the current selected network in the cubit", + () async { + sut.updateAppNetwork(AppNetworks.scroll); + expect(sut.currentChainId, AppNetworks.scroll.chainId); + }); } diff --git a/test/app/app_layout_test.dart b/test/app/app_layout_test.dart index 373fcf2..af0f33e 100644 --- a/test/app/app_layout_test.dart +++ b/test/app/app_layout_test.dart @@ -38,7 +38,7 @@ void main() { instanceName: InjectInstanceNames.appScrollController, ); - when(() => appCubit.selectedNetwork).thenReturn(Networks.mainnet); + when(() => appCubit.selectedNetwork).thenReturn(AppNetworks.mainnet); when(() => appCubit.state).thenReturn(const AppState.standard()); when(() => appCubit.isTestnetMode).thenReturn(false); when(() => appCubit.stream).thenAnswer((_) => const Stream.empty()); 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 f0940a9..238a8c0 100644 --- a/test/app/create/create_page_select_token_stage_test.dart +++ b/test/app/create/create_page_select_token_stage_test.dart @@ -11,7 +11,6 @@ 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/dtos/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/injections.dart'; import 'package:zup_app/core/repositories/tokens_repository.dart'; @@ -28,28 +27,33 @@ void main() { late TokensRepository tokensRepository; late Wallet wallet; late Cache cache; + late ZupNavigator zupNavigator; setUp(() { appCubit = AppCubitMock(); tokensRepository = TokensRepositoryMock(); wallet = WalletMock(); + zupNavigator = ZupNavigatorMock(); - registerFallbackValue(Networks.sepolia); + registerFallbackValue(AppNetworks.sepolia); cache = CacheMock(); inject.registerFactory(() => appCubit); inject.registerFactory(() => mockZupCachedImage()); inject.registerFactory(() => Debouncer(milliseconds: 0)); - inject.registerFactory(() => ZupNavigatorMock()); + inject.registerFactory(() => zupNavigator); inject.registerFactory(() => cache); inject.registerLazySingleton( () => TokenSelectorModalCubit(tokensRepository, appCubit, wallet), ); when(() => cache.getPoolSearchSettings()).thenReturn(PoolSearchSettingsDto.fixture()); - when(() => appCubit.selectedNetwork).thenAnswer((_) => Networks.sepolia); + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.sepolia); when(() => appCubit.selectedNetworkStream).thenAnswer((_) => const Stream.empty()); - when(() => tokensRepository.getTokenList(any())).thenAnswer((_) async => TokenListDto.fixture()); + when(() => tokensRepository.getPopularTokens(any())).thenAnswer((_) async => [ + TokenDto.fixture(), + TokenDto.fixture(), + ]); }); tearDown(() => inject.reset()); @@ -62,7 +66,7 @@ void main() { zGoldenTest( "When loading the page, it should select only the A token as the default token for the selected network (the token B should not be selected)", goldenFileName: "create_page_select_tokens_stage_default_a_token", (tester) async { - when(() => appCubit.selectedNetwork).thenAnswer((_) => Networks.sepolia); + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.sepolia); await tester.pumpDeviceBuilder(await goldenBuilder()); await tester.pumpAndSettle(); @@ -70,7 +74,7 @@ void main() { zGoldenTest("When the device is mobile, it should have a horizontal padding, and less padding on the top", goldenFileName: "create_page_select_tokens_stage_mobile", (tester) async { - when(() => appCubit.selectedNetwork).thenAnswer((_) => Networks.sepolia); + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.sepolia); await tester.pumpDeviceBuilder(await goldenBuilder(isMobile: true)); await tester.pumpAndSettle(); @@ -79,15 +83,11 @@ void main() { zGoldenTest( "When selecting the B token with the same address as A token, it should change the A token to null, and the B token to the selected token", goldenFileName: "create_page_select_tokens_stage_change_b_token_to_same_token_as_a", (tester) async { - const selectedNetwork = Networks.sepolia; + const selectedNetwork = AppNetworks.sepolia; final token0 = selectedNetwork.wrappedNative; - when(() => tokensRepository.getTokenList(any())).thenAnswer( - (_) async => TokenListDto.fixture().copyWith( - mostUsedTokens: [token0], - popularTokens: [token0], - userTokens: [token0], - ), + when(() => tokensRepository.getPopularTokens(any())).thenAnswer( + (_) async => [token0], ); when(() => appCubit.selectedNetwork).thenReturn(selectedNetwork); @@ -103,15 +103,12 @@ void main() { zGoldenTest( "When selecting the A token with the same address as B token, it should change the B token to null and the A token to the selected token", goldenFileName: "create_page_select_tokens_stage_change_a_token_to_same_token_as_b", (tester) async { - const selectedNetwork = Networks.sepolia; + const selectedNetwork = AppNetworks.sepolia; final token0 = selectedNetwork.wrappedNative; - when(() => tokensRepository.getTokenList(any())).thenAnswer( - (_) async => TokenListDto.fixture().copyWith( - mostUsedTokens: [token0], - popularTokens: [token0], - userTokens: [token0], - ), + when(() => appCubit.currentChainId).thenReturn(selectedNetwork.chainId); + when(() => tokensRepository.getPopularTokens(any())).thenAnswer( + (_) async => [token0], ); when(() => appCubit.selectedNetwork).thenReturn(selectedNetwork); @@ -136,7 +133,7 @@ void main() { zGoldenTest("When the token A is selected, but the token B is not, the button to find liquidity should be disabled", goldenFileName: "create_page_select_tokens_stage_token_a_selected_disabled_button", (tester) async { - const selectedNetwork = Networks.sepolia; + const selectedNetwork = AppNetworks.sepolia; when(() => appCubit.selectedNetwork).thenReturn(selectedNetwork); @@ -154,9 +151,12 @@ void main() { const token0Name = "Token1"; const token1Name = "Token2"; - when(() => tokensRepository.getTokenList(any())).thenAnswer((_) async => const TokenListDto(popularTokens: [ - TokenDto(address: "token1", name: "Token1"), - TokenDto(address: "token2", name: "Token2"), + when(() => appCubit.currentChainId).thenAnswer((_) => appCubit.selectedNetwork.chainId); + when(() => tokensRepository.getPopularTokens(any())).thenAnswer((_) async => ([ + TokenDto(addresses: {appCubit.selectedNetwork.chainId: "token1"}, name: "Token1"), + TokenDto(addresses: { + appCubit.selectedNetwork.chainId: "token2", + }, name: "Token2"), ])); await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); @@ -175,17 +175,18 @@ void main() { zGoldenTest("""When tokens are selected, but the app cubit notify about the app network change, it should reset the tokens.""", goldenFileName: "create_page_select_tokens_stage_reset_tokens_from_network", (tester) async { - final networkStream = StreamController(); + final networkStream = StreamController(); when(() => appCubit.selectedNetworkStream).thenAnswer((_) => networkStream.stream); + when(() => appCubit.currentChainId).thenAnswer((_) => appCubit.selectedNetwork.chainId); const token0Name = "Token1"; const token1Name = "Token2"; - when(() => tokensRepository.getTokenList(any())).thenAnswer((_) async => const TokenListDto(popularTokens: [ - TokenDto(address: "token1", name: "Token1"), - TokenDto(address: "token2", name: "Token2"), - ])); + when(() => tokensRepository.getPopularTokens(any())).thenAnswer((_) async => [ + TokenDto(addresses: {appCubit.selectedNetwork.chainId: "token1"}, name: "Token1"), + TokenDto(addresses: {appCubit.selectedNetwork.chainId: "token2"}, name: "Token2"), + ]); await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); @@ -199,7 +200,7 @@ void main() { await tester.tap(find.text(token1Name)); await tester.pumpAndSettle(); - networkStream.add(Networks.mainnet); + networkStream.add(AppNetworks.mainnet); }); zGoldenTest( @@ -263,4 +264,40 @@ void main() { await tester.pumpAndSettle(); }, ); + + zGoldenTest( + "When the network is all networks, clicking the search button should pass the internal ids as token ids to the next stage", + (tester) async { + const token0Id = "32"; + const token1Id = "87"; + + final tokens = [ + TokenDto.fixture() + .copyWith(name: "TokenA", internalId: token0Id, addresses: {appCubit.selectedNetwork.chainId: token0Id}), + TokenDto.fixture() + .copyWith(name: "TokenB", internalId: token1Id, addresses: {appCubit.selectedNetwork.chainId: token1Id}), + ]; + + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.allNetworks); + when(() => tokensRepository.getPopularTokens(any())).thenAnswer((_) async => tokens); + when(() => zupNavigator.navigateToDeposit(any(), any(), any())).thenAnswer((_) async {}); + + await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); + + await tester.tap(find.byKey(const Key("token-a-selector"))); + await tester.pumpAndSettle(); + await tester.tap(find.text(tokens[0].name).first); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("token-b-selector"))); + await tester.pumpAndSettle(); + await tester.tap(find.text(tokens[1].name).first); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("search-button"))); + await tester.pumpAndSettle(); + + verify(() => zupNavigator.navigateToDeposit(token0Id, token1Id, AppNetworks.allNetworks)); + }, + ); } diff --git a/test/app/create/create_page_test.dart b/test/app/create/create_page_test.dart index 71ec8d3..49a6888 100644 --- a/test/app/create/create_page_test.dart +++ b/test/app/create/create_page_test.dart @@ -27,7 +27,7 @@ void main() { inject.registerFactory(() => ZupNavigatorMock()); when(() => cache.getPoolSearchSettings()).thenReturn(PoolSearchSettingsDto.fixture()); - when(() => appCubit.selectedNetwork).thenAnswer((_) => Networks.sepolia); + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.sepolia); when(() => appCubit.selectedNetworkStream).thenAnswer((_) => const Stream.empty()); }); diff --git a/test/app/create/deposit/deposit_cubit_test.dart b/test/app/create/deposit/deposit_cubit_test.dart index 0c2fc8b..61faa6c 100644 --- a/test/app/create/deposit/deposit_cubit_test.dart +++ b/test/app/create/deposit/deposit_cubit_test.dart @@ -10,7 +10,6 @@ import 'package:zup_app/core/cache.dart'; import 'package:zup_app/core/dtos/deposit_settings_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_by_timeframe_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'; @@ -35,7 +34,7 @@ void main() { setUp(() { registerFallbackValue(DepositSettingsDto.fixture()); - registerFallbackValue(Networks.sepolia); + registerFallbackValue(AppNetworks.sepolia); yieldRepository = YieldRepositoryMock(); zupSingletonCache = ZupSingletonCache.shared; @@ -56,7 +55,15 @@ void main() { zupAnalytics, ); - when(() => appCubit.selectedNetwork).thenAnswer((_) => Networks.sepolia); + when(() => appCubit.isTestnetMode).thenReturn(false); + + when(() => yieldRepository.getAllNetworksYield( + token0InternalId: any(named: "token0InternalId"), + token1InternalId: any(named: "token1InternalId"), + minTvlUsd: any(named: "minTvlUsd"), + testnetMode: any(named: "testnetMode"))).thenAnswer((_) async => YieldsDto.fixture()); + + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.sepolia); when(() => cache.getPoolSearchSettings()).thenReturn(PoolSearchSettingsDto.fixture()); when( () => uniswapV3Pool.fromRpcProvider(contractAddress: any(named: "contractAddress"), rpcUrl: any(named: "rpcUrl")), @@ -79,6 +86,8 @@ void main() { tick: poolTick, unlocked: true )); + + when(() => cache.getPoolSearchSettings()).thenReturn(PoolSearchSettingsDto(minLiquidityUSD: 129816)); }); tearDown(() async { @@ -92,7 +101,8 @@ void main() { const minutesPassed = 3; final selectedYield = YieldDto.fixture(); - await sut.selectYield(selectedYield); + const selectedTimeframe = YieldTimeFrame.day; + await sut.selectYield(selectedYield, selectedTimeframe); fakeAsync((async) { sut.setup(); @@ -120,7 +130,7 @@ void main() { int eventsCounter = 0; const minutesPassed = 3; - await sut.selectYield(null); + await sut.selectYield(null, null); fakeAsync((async) { sut.setup(); @@ -141,7 +151,7 @@ void main() { it should not execute the task to get the pool tick and cancel the periodic task""", () async { final selectedYield = YieldDto.fixture(); - await sut.selectYield(selectedYield); + await sut.selectYield(selectedYield, YieldTimeFrame.day); int eventCount = 0; fakeAsync((async) { @@ -163,11 +173,11 @@ void main() { test("When calling `getBestPools` it should emit the loading state", () async { expectLater(sut.stream, emits(const DepositState.loading())); - await sut.getBestPools(token0Address: "", token1Address: ""); + await sut.getBestPools(token0AddressOrId: "", token1AddressOrId: ""); }); test("When calling `getBestPools` it should call the yield repository to get the best pools", () async { - when(() => yieldRepository.getYields( + when(() => yieldRepository.getSingleNetworkYield( token0Address: any(named: "token0Address"), token1Address: any(named: "token1Address"), minTvlUsd: any(named: "minTvlUsd"), @@ -178,9 +188,9 @@ void main() { const token0Address = "token0Address"; const token1Address = "token1Address"; - await sut.getBestPools(token0Address: token0Address, token1Address: token1Address); + await sut.getBestPools(token0AddressOrId: token0Address, token1AddressOrId: token1Address); - verify(() => yieldRepository.getYields( + verify(() => yieldRepository.getSingleNetworkYield( token0Address: token0Address, token1Address: token1Address, minTvlUsd: any(named: "minTvlUsd"), @@ -193,12 +203,12 @@ void main() { from the repository""", () async { const minLiquidityUSD = 123; - when(() => yieldRepository.getYields( + when(() => yieldRepository.getSingleNetworkYield( token0Address: any(named: "token0Address"), token1Address: any(named: "token1Address"), minTvlUsd: any(named: "minTvlUsd"), network: any(named: "network"))).thenAnswer( - (_) async => YieldsDto(timeframedYields: YieldsByTimeframeDto.empty(), minLiquidityUSD: minLiquidityUSD), + (_) async => const YieldsDto(pools: [], minLiquidityUSD: minLiquidityUSD), ); expectLater( @@ -208,13 +218,13 @@ void main() { const DepositState.noYields(minLiquiditySearched: minLiquidityUSD), ])); - await sut.getBestPools(token0Address: "", token1Address: ""); + await sut.getBestPools(token0AddressOrId: "", token1AddressOrId: ""); }); test("When calling `getBestPools` and receiving a list of pools it should emit success state", () async { final pools = YieldsDto.fixture(); - when(() => yieldRepository.getYields( + when(() => yieldRepository.getSingleNetworkYield( token0Address: any(named: "token0Address"), token1Address: any(named: "token1Address"), minTvlUsd: any(named: "minTvlUsd"), @@ -222,11 +232,11 @@ void main() { expectLater(sut.stream, emitsInOrder([const DepositState.loading(), DepositState.success(pools)])); - await sut.getBestPools(token0Address: "", token1Address: ""); + await sut.getBestPools(token0AddressOrId: "", token1AddressOrId: ""); }); test("When calling `getBestPools` and receiving an error, it should emit the error state", () async { - when(() => yieldRepository.getYields( + when(() => yieldRepository.getSingleNetworkYield( token0Address: any(named: "token0Address"), token1Address: any(named: "token1Address"), minTvlUsd: any(named: "minTvlUsd"), @@ -234,13 +244,13 @@ void main() { expectLater(sut.stream, emitsInOrder([const DepositState.loading(), const DepositState.error()])); - await sut.getBestPools(token0Address: "", token1Address: ""); + await sut.getBestPools(token0AddressOrId: "", token1AddressOrId: ""); }); test("When calling `selectYield` it should save the selected yield in a variable", () async { final selectedYield = YieldDto.fixture(); - await sut.selectYield(selectedYield); + await sut.selectYield(selectedYield, YieldTimeFrame.day); expect(sut.selectedYield, selectedYield); }); @@ -250,19 +260,19 @@ void main() { expectLater(sut.selectedYieldStream, emits(selectedYield)); - await sut.selectYield(selectedYield); + await sut.selectYield(selectedYield, YieldTimeFrame.day); }); test("When calling `selectYield` with a non-empty yield it should get the pool tick", () async { final selectedYield = YieldDto.fixture(); - await sut.selectYield(selectedYield); + await sut.selectYield(selectedYield, YieldTimeFrame.day); verify(() => uniswapV3PoolImpl.slot0()).called(1); }); test("When calling `selectYield` but the yield is null, it should not get the pool tick", () async { - await sut.selectYield(null); + await sut.selectYield(null, null); verifyNever(() => uniswapV3PoolImpl.slot0()); }); @@ -270,14 +280,14 @@ void main() { test("When calling `getSelectedPoolTick` it should set the latest pool tick to null", () async { expectLater(sut.latestPoolTick, null); - await sut.selectYield(YieldDto.fixture()); + await sut.selectYield(YieldDto.fixture(), YieldTimeFrame.day); await sut.getSelectedPoolTick(); }); test("When calling `getSelectedPoolTick` it should emit a null pool tick before getting the pool tick", () async { expectLater(sut.poolTickStream, emits(null)); - await sut.selectYield(YieldDto.fixture()); + await sut.selectYield(YieldDto.fixture(), YieldTimeFrame.day); await sut.getSelectedPoolTick(); }); @@ -286,7 +296,7 @@ void main() { pool""", () async { final selectedYield = YieldDto.fixture(); - await sut.selectYield(YieldDto.fixture()); + await sut.selectYield(YieldDto.fixture(), YieldTimeFrame.day); await sut.getSelectedPoolTick(); verify( @@ -298,7 +308,7 @@ void main() { }); test("When calling `getSelectedPoolTick` it should use the slot0 from the UniswapV3Pool contract", () async { - await sut.selectYield(YieldDto.fixture()); + await sut.selectYield(YieldDto.fixture(), YieldTimeFrame.day); await sut.getSelectedPoolTick(); verify(() => uniswapV3PoolImpl.slot0()).called(2); // 2 because of the `selectYield` and the `getSelectedPoolTick` @@ -331,7 +341,7 @@ void main() { ); }); - await sut.selectYield(yieldB); + await sut.selectYield(yieldB, YieldTimeFrame.day); return ( feeProtocol: BigInt.zero, @@ -344,7 +354,7 @@ void main() { ); }); - await sut.selectYield(yieldA); // assuming that select yield will call `getSelectedPoolTick` + await sut.selectYield(yieldA, YieldTimeFrame.day); // assuming that select yield will call `getSelectedPoolTick` verify( () => uniswapV3Pool.fromRpcProvider(contractAddress: yieldBPoolAddress, rpcUrl: yieldB.network.rpcUrl), @@ -368,7 +378,8 @@ void main() { expectLater(sut.poolTickStream, emitsInOrder([null, expectedPoolTick])); - await sut.selectYield(YieldDto.fixture()); // assuming that select yield will call `getSelectedPoolTick` + await sut.selectYield( + YieldDto.fixture(), YieldTimeFrame.day); // assuming that select yield will call `getSelectedPoolTick` }); test("When calling `getSelectedPoolTick` it should save the pool tick in the cubit", () async { @@ -384,7 +395,8 @@ void main() { unlocked: true )); - await sut.selectYield(YieldDto.fixture()); // assuming that select yield will call `getSelectedPoolTick` + await sut.selectYield( + YieldDto.fixture(), YieldTimeFrame.day); // assuming that select yield will call `getSelectedPoolTick` expect(sut.latestPoolTick, expectedPoolTick); }); @@ -403,13 +415,14 @@ void main() { )); expectLater(sut.poolTickStream, emitsInOrder([null, expectedPoolTick])); - await sut.selectYield(YieldDto.fixture()); // assuming that select yield will call `getSelectedPoolTick` + await sut.selectYield( + YieldDto.fixture(), YieldTimeFrame.day); // assuming that select yield will call `getSelectedPoolTick` expect(sut.latestPoolTick, expectedPoolTick); }); test("when closing the cubit, it should close the pool tick stream", () async { - await sut.selectYield(YieldDto.fixture()); + await sut.selectYield(YieldDto.fixture(), YieldTimeFrame.day); await sut.close(); expect( @@ -422,13 +435,13 @@ void main() { await sut.close(); expect( - () async => await sut.selectYield(YieldDto.fixture()), + () async => await sut.selectYield(YieldDto.fixture(), YieldTimeFrame.day), throwsA(isA()), ); }); test("When calling `getWalletTokenAmount` and there's no connected signer, it should return 0", () async { - final tokenAmount = await sut.getWalletTokenAmount("", network: Networks.sepolia); + final tokenAmount = await sut.getWalletTokenAmount("", network: AppNetworks.sepolia); expect(tokenAmount, 0); }); @@ -437,7 +450,7 @@ void main() { () async { final signer = SignerMock(); const tokenAddress = "0x0"; - const network = Networks.sepolia; + const network = AppNetworks.sepolia; const expectedTokenBalance = 1243.542; when(() => wallet.tokenBalance(tokenAddress, rpcUrl: any(named: "rpcUrl"))).thenAnswer((_) async => 1243.542); @@ -455,7 +468,7 @@ void main() { () async { const tokenAddress = "0x0"; final signer = SignerMock(); - const network = Networks.sepolia; + const network = AppNetworks.sepolia; const expectedTokenBalance = 1243.542; const notExpectedTokenBalance = 498361387.42; @@ -481,7 +494,7 @@ void main() { () async { const tokenAddress = "0x0"; final signer = SignerMock(); - const network = Networks.sepolia; + const network = AppNetworks.sepolia; const expectedTokenBalance = 1243.542; const notExpectedTokenBalance = 498361387.42; @@ -510,7 +523,7 @@ void main() { () async { final signer = SignerMock(); const tokenAddress = "0x0"; - const network = Networks.sepolia; + const network = AppNetworks.sepolia; when(() => wallet.tokenBalance(tokenAddress, rpcUrl: any(named: "rpcUrl"))).thenThrow(Exception()); when(() => wallet.signer).thenReturn(signer); @@ -569,16 +582,16 @@ void main() { it should pass the minLiquidityUSD as 0 to the repository""", () async { when(() => cache.getPoolSearchSettings()).thenReturn(PoolSearchSettingsDto(minLiquidityUSD: 129816)); - when(() => yieldRepository.getYields( + when(() => yieldRepository.getSingleNetworkYield( token0Address: any(named: "token0Address"), token1Address: any(named: "token1Address"), network: any(named: "network"), minTvlUsd: any(named: "minTvlUsd"), )).thenAnswer((_) async => YieldsDto.fixture()); - await sut.getBestPools(token0Address: "0x", token1Address: "0x", ignoreMinLiquidity: true); + await sut.getBestPools(token0AddressOrId: "0x", token1AddressOrId: "0x", ignoreMinLiquidity: true); - verify(() => yieldRepository.getYields( + verify(() => yieldRepository.getSingleNetworkYield( token0Address: any(named: "token0Address"), token1Address: any(named: "token1Address"), network: any(named: "network"), @@ -591,16 +604,16 @@ void main() { const minLiquiditySaved = 129816; when(() => cache.getPoolSearchSettings()).thenReturn(PoolSearchSettingsDto(minLiquidityUSD: minLiquiditySaved)); - when(() => yieldRepository.getYields( + when(() => yieldRepository.getSingleNetworkYield( token0Address: any(named: "token0Address"), token1Address: any(named: "token1Address"), network: any(named: "network"), minTvlUsd: any(named: "minTvlUsd"), )).thenAnswer((_) async => YieldsDto.fixture()); - await sut.getBestPools(token0Address: "0x", token1Address: "0x", ignoreMinLiquidity: false); + await sut.getBestPools(token0AddressOrId: "0x", token1AddressOrId: "0x", ignoreMinLiquidity: false); - verify(() => yieldRepository.getYields( + verify(() => yieldRepository.getSingleNetworkYield( token0Address: any(named: "token0Address"), token1Address: any(named: "token1Address"), network: any(named: "network"), @@ -613,14 +626,40 @@ void main() { () { const token0Address = "0x123"; const token1Address = "0x456"; - const network = Networks.sepolia; + const network = AppNetworks.sepolia; when(() => appCubit.selectedNetwork).thenReturn(network); - sut.getBestPools(token0Address: token0Address, token1Address: token1Address); + sut.getBestPools(token0AddressOrId: token0Address, token1AddressOrId: token1Address); verify(() => zupAnalytics.logSearch(token0: token0Address, token1: token1Address, network: network.label)) .called(1); }, ); + + test( + "When calling `getBestPools` and the network is all networks, it should call the endpoint to search in all networks", + () async { + const token0Address = "0x123"; + const token1Address = "0x456"; + + when(() => appCubit.selectedNetwork).thenReturn(AppNetworks.allNetworks); + + await sut.getBestPools(token0AddressOrId: token0Address, token1AddressOrId: token1Address); + + verify(() => yieldRepository.getAllNetworksYield( + token0InternalId: token0Address, + token1InternalId: token1Address, + minTvlUsd: any(named: "minTvlUsd"), + )).called(1); + }); + + test("When calling 'selectYield' it should update the selected time frame as well to the one passed", () async { + final selectedYield = YieldDto.fixture(); + const selectedYieldTimeFrame = YieldTimeFrame.day; + + await sut.selectYield(selectedYield, selectedYieldTimeFrame); + + expect(sut.selectedYieldTimeframe, selectedYieldTimeFrame); + }); } diff --git a/test/app/create/deposit/deposit_page_test.dart b/test/app/create/deposit/deposit_page_test.dart index c1754d1..ba9ef20 100644 --- a/test/app/create/deposit/deposit_page_test.dart +++ b/test/app/create/deposit/deposit_page_test.dart @@ -19,7 +19,6 @@ import 'package:zup_app/core/cache.dart'; import 'package:zup_app/core/dtos/deposit_settings_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_by_timeframe_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/zup_navigator_paths.dart'; @@ -57,7 +56,7 @@ void main() { cache = CacheMock(); registerFallbackValue(BuildContextMock()); - registerFallbackValue(Networks.sepolia); + registerFallbackValue(AppNetworks.sepolia); registerFallbackValue(Slippage.fromValue(32)); registerFallbackValue(DepositSettingsDto.fixture()); registerFallbackValue(Duration.zero); @@ -103,13 +102,13 @@ void main() { when(() => cubit.stream).thenAnswer((_) => const Stream.empty()); when(() => cubit.state).thenAnswer((_) => const DepositState.initial()); when(() => cubit.getBestPools( - token0Address: any(named: "token0Address"), - token1Address: any(named: "token1Address"), + token0AddressOrId: any(named: "token0AddressOrId"), + token1AddressOrId: any(named: "token1AddressOrId"), ignoreMinLiquidity: any(named: "ignoreMinLiquidity"), )).thenAnswer((_) async {}); when(() => cache.getPoolSearchSettings()).thenReturn(PoolSearchSettingsDto.fixture()); when(() => cubit.selectedYieldStream).thenAnswer((_) => const Stream.empty()); - when(() => appCubit.selectedNetwork).thenReturn(Networks.sepolia); + when(() => appCubit.selectedNetwork).thenReturn(AppNetworks.sepolia); when(() => cubit.poolTickStream).thenAnswer((_) => const Stream.empty()); when(() => cubit.latestPoolTick).thenAnswer((_) => BigInt.from(32523672)); when(() => wallet.signerStream).thenAnswer((_) => const Stream.empty()); @@ -117,6 +116,7 @@ void main() { when(() => cubit.saveDepositSettings(any(), any())).thenAnswer((_) async => ()); when(() => cubit.depositSettings).thenReturn(DepositSettingsDto.fixture()); when(() => cubit.poolSearchSettings).thenReturn(PoolSearchSettingsDto.fixture()); + when(() => cubit.selectedYieldTimeframe).thenReturn(YieldTimeFrame.day); }); tearDown(() async { @@ -154,8 +154,8 @@ void main() { verify( () => cubit.getBestPools( - token0Address: token0Address, - token1Address: token1Address, + token0AddressOrId: token0Address, + token1AddressOrId: token1Address, ), ).called(1); }); @@ -198,8 +198,8 @@ void main() { (tester) async { when( () => cubit.getBestPools( - token0Address: any(named: "token0Address"), - token1Address: any(named: "token1Address"), + token0AddressOrId: any(named: "token0AddressOrId"), + token1AddressOrId: any(named: "token1AddressOrId"), ignoreMinLiquidity: any(named: "ignoreMinLiquidity")), ).thenAnswer((_) async {}); @@ -212,8 +212,8 @@ void main() { verify( () => cubit.getBestPools( - token0Address: any(named: "token0Address"), - token1Address: any(named: "token1Address"), + token0AddressOrId: any(named: "token0AddressOrId"), + token1AddressOrId: any(named: "token1AddressOrId"), ignoreMinLiquidity: true, ), ).called(1); @@ -257,7 +257,7 @@ void main() { await tester.tap(find.byKey(const Key("help-button"))); await tester.pumpAndSettle(); - verify(() => cubit.getBestPools(token0Address: token0Address, token1Address: token1Address)) + verify(() => cubit.getBestPools(token0AddressOrId: token0Address, token1AddressOrId: token1Address)) .called(2); // 2 because of the initial call }); @@ -316,8 +316,8 @@ void main() { when(() => cubit.poolSearchSettings).thenReturn(PoolSearchSettingsDto(minLiquidityUSD: 12675)); when(() => cubit.state).thenReturn(DepositState.success(yields)); when(() => cubit.getBestPools( - token0Address: any(named: "token0Address"), - token1Address: any(named: "token1Address"), + token0AddressOrId: any(named: "token0AddressOrId"), + token1AddressOrId: any(named: "token1AddressOrId"), ignoreMinLiquidity: any(named: "ignoreMinLiquidity"))).thenAnswer((_) async {}); await tester.pumpDeviceBuilder(await goldenBuilder()); @@ -327,8 +327,8 @@ void main() { verify( () => cubit.getBestPools( - token0Address: any(named: "token0Address"), - token1Address: any(named: "token1Address"), + token0AddressOrId: any(named: "token0AddressOrId"), + token1AddressOrId: any(named: "token1AddressOrId"), ignoreMinLiquidity: true, ), ).called(1); @@ -341,8 +341,8 @@ void main() { when(() => cubit.poolSearchSettings).thenReturn(PoolSearchSettingsDto(minLiquidityUSD: 12675)); // local filter set when(() => cubit.state).thenReturn(DepositState.success(yields)); when(() => cubit.getBestPools( - token0Address: any(named: "token0Address"), - token1Address: any(named: "token1Address"), + token0AddressOrId: any(named: "token0AddressOrId"), + token1AddressOrId: any(named: "token1AddressOrId"), ignoreMinLiquidity: any(named: "ignoreMinLiquidity"))).thenAnswer((_) async {}); await tester.pumpDeviceBuilder(await goldenBuilder()); @@ -352,8 +352,8 @@ void main() { verify( () => cubit.getBestPools( - token0Address: any(named: "token0Address"), - token1Address: any(named: "token1Address"), + token0AddressOrId: any(named: "token0AddressOrId"), + token1AddressOrId: any(named: "token1AddressOrId"), ignoreMinLiquidity: false, ), ).called(2); // two calls, one when the page is loaded and one when the user clicks the button @@ -446,7 +446,7 @@ void main() { zGoldenTest("When the selected yield stream in the cubit emits a yield, it should select the yield", goldenFileName: "deposit_page_selected_yield_stream", (tester) async { final yields = YieldsDto.fixture(); - final selectedYield = yields.timeframedYields.best24hYields.first; + final selectedYield = yields.best24hYield; when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); when(() => cubit.selectedYield).thenReturn(selectedYield); @@ -457,7 +457,7 @@ void main() { }); zGoldenTest("When selecting a yield, it should call select yield in the cubit", (tester) async { - when(() => cubit.selectYield(any())).thenAnswer((_) async {}); + when(() => cubit.selectYield(any(), any())).thenAnswer((_) async {}); when(() => cubit.state).thenReturn(DepositState.success(YieldsDto.fixture())); await tester.pumpDeviceBuilder(await goldenBuilder()); @@ -465,16 +465,15 @@ void main() { await tester.tap(find.byKey(const Key("yield-card-24h"))); await tester.pumpAndSettle(); - verify(() => cubit.selectYield(any())).called(1); + verify(() => cubit.selectYield(any(), any())).called(1); }); zGoldenTest("When selecting a yield, it should scroll down to the range section", goldenFileName: "deposit_page_select_yield_scroll", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; - + final selectedYield = YieldsDto.fixture().best24hYield; when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); when(() => cubit.selectedYield).thenReturn(null); - when(() => cubit.selectYield(any())).thenAnswer((_) async {}); + when(() => cubit.selectYield(any(), any())).thenAnswer((_) async {}); when(() => cubit.state).thenReturn(DepositState.success(YieldsDto.fixture())); when(() => cubit.selectedYield).thenReturn(selectedYield); @@ -483,49 +482,13 @@ void main() { await tester.tap(find.byKey(const Key("yield-card-30d"))); await tester.pumpAndSettle(); - verify(() => cubit.selectYield(any())).called(1); - }); - - zGoldenTest("When there is not yields in 24h, it should not show the 24h card", goldenFileName: "deposit_page_no_24h", - (tester) async { - final yields = YieldsDto.fixture().copyWith( - timeframedYields: YieldsByTimeframeDto.fixture().copyWith(best24hYields: []), - ); - - when(() => cubit.state).thenReturn(DepositState.success(yields)); - - await tester.pumpDeviceBuilder(await goldenBuilder()); - }); - - zGoldenTest("When there is not yields in 30d, it should not show the 30d card", goldenFileName: "deposit_page_no_30d", - (tester) async { - final yields = YieldsDto.fixture().copyWith( - timeframedYields: YieldsByTimeframeDto.fixture().copyWith(best30dYields: []), - ); - - when(() => cubit.state).thenReturn(DepositState.success(yields)); - - await tester.pumpDeviceBuilder(await goldenBuilder()); - - await tester.pumpAndSettle(); - }); - - zGoldenTest("When there is not yields in 3months, it should not show the 3months card", - goldenFileName: "deposit_page_no_3months", (tester) async { - final yields = YieldsDto.fixture().copyWith( - timeframedYields: YieldsByTimeframeDto.fixture().copyWith(best90dYields: []), - ); - when(() => cubit.state).thenReturn(DepositState.success(yields)); - - await tester.pumpDeviceBuilder(await goldenBuilder()); - - await tester.pumpAndSettle(); + verify(() => cubit.selectYield(any(), any())).called(1); }); zGoldenTest( "When clicking the segmented control to switch the base token to quote token, it should reverse the tokens", goldenFileName: "deposit_page_reverse_tokens", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); when(() => cubit.selectedYield).thenReturn(selectedYield); @@ -540,7 +503,7 @@ void main() { zGoldenTest( "When clicking the segmented control to switch back to base token, after reversing the tokens, it should reverse again", goldenFileName: "deposit_page_reverse_tokens_back", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); when(() => cubit.selectedYield).thenReturn(selectedYield); @@ -558,7 +521,7 @@ void main() { zGoldenTest( "When clicking the segmented control to switch back to base token, after reversing the tokens, it should reverse again", goldenFileName: "deposit_page_reverse_tokens_back", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); when(() => cubit.selectedYield).thenReturn(selectedYield); @@ -576,7 +539,7 @@ void main() { zGoldenTest("""When emitting an event to the tick stream, it should calculate the price of the selected yield assets""", goldenFileName: "deposit_page_calculate_price", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); when(() => cubit.selectedYield).thenReturn(selectedYield); @@ -589,7 +552,7 @@ void main() { zGoldenTest( "When reversing the tokens, it should calculate the price based on the reversed tokens, from a given tick in the cubit", goldenFileName: "deposit_page_calculate_price_reversed", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); when(() => cubit.selectedYield).thenReturn(selectedYield); @@ -606,7 +569,7 @@ void main() { "When typing a min price more than the current price, it should show an alert saying that is out of range", goldenFileName: "deposit_page_min_price_out_of_range", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -631,7 +594,7 @@ void main() { is not out of range, it should not show the alert""", goldenFileName: "deposit_page_min_price_out_of_range_reversed_in_range", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -657,7 +620,7 @@ void main() { is is still out of range, it should keep showing the alert""", goldenFileName: "deposit_page_min_price_out_of_range_reversed", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -678,7 +641,7 @@ void main() { zGoldenTest("When typing a max price less than the min price, it should show an error message", goldenFileName: "deposit_page_max_price_less_than_min_price", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -699,7 +662,7 @@ void main() { zGoldenTest("""When typing a max price lower than the current price but higher than min price, it shouw show a alert of out of range""", goldenFileName: "deposit_page_max_price_out_of_range", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -719,7 +682,7 @@ void main() { zGoldenTest("When typing 0 in the max price, it should set it to infinity max price", goldenFileName: "deposit_page_max_price_set_to_infinity", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -746,7 +709,7 @@ void main() { zGoldenTest("When typing a min price, but then selecting the full range button, it should set it to 0", goldenFileName: "deposit_page_min_price_set_to_full_range", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -766,7 +729,7 @@ void main() { zGoldenTest("When typing a max price, but then selecting the full range button, it should set it to infinity", goldenFileName: "deposit_page_max_price_set_to_full_range", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -787,7 +750,7 @@ void main() { zGoldenTest("""When typing a min and max price and then clicking the full range button, it should set the min price to 0 and the max price to infinity""", goldenFileName: "deposit_page_min_and_max_price_set_to_full_range", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -811,7 +774,7 @@ void main() { zGoldenTest( "When there's a invalid range, the deposit section should be disabled (with opacity) and cannot be clicked or typed", goldenFileName: "deposit_page_invalid_range_deposit_section", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -838,7 +801,7 @@ void main() { "When inputing the base token amount, the quote amount token should be automatically calculated", goldenFileName: "deposit_page_input_base_token_amount", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -860,7 +823,7 @@ void main() { "When inputing the quote token amount, the base amount token should be automatically calculated", goldenFileName: "deposit_page_input_quote_token_amount", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -884,7 +847,7 @@ void main() { and the new base token amount should be automatically calculated""", goldenFileName: "deposit_page_input_base_token_amount_and_reverse", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -911,7 +874,7 @@ void main() { and the new quote token amount should be automatically calculated""", goldenFileName: "deposit_page_input_quote_token_amount_and_reverse", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -936,7 +899,7 @@ void main() { """When inputing the base token amount with the tokens reversed, the quote token amount should be automatically calculated""", goldenFileName: "deposit_page_input_base_token_amount_reversed", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -961,7 +924,7 @@ void main() { """When inputing the quote token amount with the tokens reversed, the base token amount should be automatically calculated""", goldenFileName: "deposit_page_input_quote_token_amount_reversed", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -986,7 +949,7 @@ void main() { then turning them normal, the quote token amount should now be the previous base token amount, and the new base token amount should be automatically calculated""", goldenFileName: "deposit_page_input_base_token_amount_and_reverse_back", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1013,7 +976,7 @@ void main() { then turning them normal, the base token amount should now be the previous quote token amount, and the new quote token amount should be automatically calculated""", goldenFileName: "deposit_page_input_quote_token_amount_and_reverse_back", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1040,7 +1003,7 @@ void main() { "When inputing the base token amount, then changing the range, the quote token amount should be recalculated", goldenFileName: "deposit_page_input_base_token_amount_and_change_range", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1072,7 +1035,7 @@ void main() { "When inputing the quote token amount, then changing the range, the base token amount should be recalculated", goldenFileName: "deposit_page_input_quote_token_amount_and_change_range", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1104,7 +1067,7 @@ void main() { zGoldenTest( "When inputing the base token amount, reversing the tokens and then changing the range, the base token amount should be recalculated", goldenFileName: "deposit_page_input_base_token_amount_reverse_tokens_and_change_range", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1138,7 +1101,7 @@ void main() { zGoldenTest( "When inputing the quote token amount, reversing the tokens and then changing the range, the quote token amount should be recalculated", goldenFileName: "deposit_page_input_quote_token_amount_reverse_tokens_and_change_range", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1173,7 +1136,7 @@ void main() { "When inputing a range, then inputing the base token amount, the quote token amount should be automatically calculated", goldenFileName: "deposit_page_input_range_then_input_base_token_amount", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1206,7 +1169,7 @@ void main() { "When inputing a range, then inputing the quote token amount, the base token amount should be automatically calculated", goldenFileName: "deposit_page_input_range_then_input_quote_token_amount", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1239,7 +1202,7 @@ void main() { "When inputing a range,reversing the tokens, then inputing the base token amount, the quote token amount should be automatically calculated", goldenFileName: "deposit_page_input_range_then_reverse_tokens_then_input_base_token_amount", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1277,7 +1240,7 @@ void main() { "When inputing a range, reversing the tokens, then inputing the quote token amount, the base token amount should be automatically calculated", goldenFileName: "deposit_page_input_range_then_reverse_tokens_then_input_quote_token_amount", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1314,7 +1277,7 @@ void main() { zGoldenTest("""When inputing base token amount, and then setting a max price out of range, it should keep the quote token amount and disable the base token input""", goldenFileName: "deposit_page_input_base_token_amount_then_set_max_price_out_of_range", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1342,7 +1305,7 @@ void main() { zGoldenTest("""When inputing quote token amount, and then setting a min price out of range, it should keep the base token amount and disable the quote token input""", goldenFileName: "deposit_page_input_quote_token_amount_then_set_min_price_out_of_range", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1368,7 +1331,7 @@ void main() { it should keep the quote token amount and disable the base token input""", goldenFileName: "deposit_page_input_base_token_amount_then_reverse_tokens_then_set_max_price_out_of_range", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1400,7 +1363,7 @@ void main() { it should keep the base token amount and disable the quote token input""", goldenFileName: "deposit_page_input_quote_token_amount_then_reverse_tokens_then_set_min_price_out_of_range", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1429,7 +1392,7 @@ void main() { "When the user is is not connected, it should show the connect wallet button instead of the deposit button", goldenFileName: "deposit_page_not_connected", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => wallet.signer).thenReturn(null); @@ -1453,7 +1416,7 @@ void main() { """, goldenFileName: "deposit_page_not_connected_deposit_button_click", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); when(() => wallet.signer).thenReturn(null); @@ -1478,7 +1441,7 @@ void main() { the deposit button should should be disabled""", goldenFileName: "deposit_page_no_amount_deposit_button", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); final signer = SignerMock(); @@ -1505,7 +1468,7 @@ void main() { the deposit button should should be disabled""", goldenFileName: "deposit_page_not_enough_base_token_balance_deposit_button", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); final signer = SignerMock(); @@ -1535,17 +1498,19 @@ void main() { the deposit button should should be disabled""", goldenFileName: "deposit_page_not_enough_quote_token_balance_deposit_button", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); final signer = SignerMock(); when(() => wallet.signer).thenReturn(signer); when(() => wallet.signerStream).thenAnswer((_) => Stream.value(signer)); - when(() => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token0.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(32567352673), ); - when(() => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token1.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(0), ); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1568,17 +1533,19 @@ void main() { without having enough balance of base token, the deposit button should should be disabled""", goldenFileName: "deposit_page_not_enough_base_token_balance_deposit_button_after_connecting", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); final signerStreamController = StreamController.broadcast(); final signer = SignerMock(); when(() => wallet.signer).thenReturn(null); when(() => wallet.signerStream).thenAnswer((_) => signerStreamController.stream); - when(() => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token0.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(0), ); - when(() => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token1.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(0), ); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1604,17 +1571,19 @@ void main() { without having enough balance of quote token, the deposit button should should be disabled""", goldenFileName: "deposit_page_not_enough_quote_token_balance_deposit_button_after_connecting", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); final signerStreamController = StreamController.broadcast(); final signer = SignerMock(); when(() => wallet.signer).thenReturn(null); when(() => wallet.signerStream).thenAnswer((_) => signerStreamController.stream); - when(() => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token0.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(347537253), ); - when(() => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token1.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(0), ); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1640,17 +1609,19 @@ void main() { the deposit button should be enabled""", goldenFileName: "deposit_page_enough_balance_deposit_button", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); final signer = SignerMock(); when(() => wallet.signer).thenReturn(signer); when(() => wallet.signerStream).thenAnswer((_) => Stream.value(signer)); - when(() => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token0.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(347537253), ); - when(() => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token1.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(32576352673), ); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1671,17 +1642,19 @@ void main() { zGoldenTest("""When the min range is out of range, and the user does not have quote token balance but has enough balance of base token, the deposit button should be enabled""", goldenFileName: "deposit_page_min_range_out_of_range_deposit_button", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); final signer = SignerMock(); when(() => wallet.signer).thenReturn(signer); when(() => wallet.signerStream).thenAnswer((_) => Stream.value(signer)); - when(() => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token0.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(347537253), ); - when(() => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token1.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(0), ); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1704,17 +1677,19 @@ void main() { zGoldenTest("""When the max range is out of range, and the user does not have base token balance but has enough balance of quote token, the deposit button should be enabled""", goldenFileName: "deposit_page_max_range_out_of_range_deposit_button", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); final signer = SignerMock(); when(() => wallet.signer).thenReturn(signer); when(() => wallet.signerStream).thenAnswer((_) => Stream.value(signer)); - when(() => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token0.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(0), ); - when(() => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token1.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(3237526), ); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -1743,19 +1718,22 @@ void main() { zGoldenTest("When clicking the enabled deposit button, it should show the preview modal of the deposit", goldenFileName: "deposit_page_preview_modal", (tester) async { await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); final signer = SignerMock(); when(() => wallet.signer).thenReturn(signer); when(() => wallet.signerStream).thenAnswer((_) => Stream.value(signer)); - when(() => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token0.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(347537253), ); - when(() => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token1.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(32576352673), ); + when(() => cubit.selectYield(any(), any())).thenAnswer((_) => Future.value()); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); when(() => cubit.selectedYield).thenReturn(selectedYield); when(() => cubit.state).thenReturn(DepositState.success(YieldsDto.fixture())); @@ -1763,6 +1741,8 @@ void main() { when(() => cubit.latestPoolTick).thenReturn(currentPriceAsTick); await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); + await tester.tap(find.byKey(const Key("yield-card-24h"))); + await tester.pumpAndSettle(); await tester.drag(find.byKey(const Key("deposit-section")), const Offset(0, -500)); await tester.pumpAndSettle(); @@ -1779,7 +1759,7 @@ void main() { the quote token input should be loading""", goldenFileName: "deposit_page_quote_token_input_loading", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); when(() => cubit.selectedYield).thenReturn(selectedYield); @@ -1801,7 +1781,7 @@ void main() { the base token input should be loading""", goldenFileName: "deposit_page_base_token_input_loading", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); when(() => cubit.selectedYield).thenReturn(selectedYield); @@ -1824,7 +1804,7 @@ void main() { """, goldenFileName: "deposit_page_quote_token_input_enabled_after_loading", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); when(() => cubit.selectedYield).thenReturn(selectedYield); @@ -1847,7 +1827,7 @@ void main() { """, goldenFileName: "deposit_page_base_token_input_enabled_after_loading", (tester) async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); when(() => cubit.selectedYield).thenReturn(selectedYield); @@ -2040,17 +2020,19 @@ void main() { const expectedDeadline = Duration(minutes: 76); await tester.runAsync(() async { - final selectedYield = YieldsDto.fixture().timeframedYields.best24hYields.first; + final selectedYield = YieldsDto.fixture().best24hYield; final currentPriceAsTick = BigInt.from(174072); final signer = SignerMock(); when(() => wallet.signer).thenReturn(signer); when(() => wallet.signerStream).thenAnswer((_) => Stream.value(signer)); - when(() => cubit.getWalletTokenAmount(selectedYield.token0.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token0.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(347537253), ); - when(() => cubit.getWalletTokenAmount(selectedYield.token1.address, network: any(named: "network"))).thenAnswer( + when(() => cubit.getWalletTokenAmount(selectedYield.token1.addresses[selectedYield.network.chainId]!, + network: any(named: "network"))).thenAnswer( (_) => Future.value(32576352673), ); when(() => cubit.selectedYieldStream).thenAnswer((_) => Stream.value(selectedYield)); @@ -2058,8 +2040,15 @@ void main() { when(() => cubit.state).thenReturn(DepositState.success(YieldsDto.fixture())); when(() => cubit.poolTickStream).thenAnswer((_) => Stream.value(currentPriceAsTick)); when(() => cubit.latestPoolTick).thenReturn(currentPriceAsTick); + when(() => cubit.selectYield(any(), any())).thenAnswer((_) async => () {}); + when(() => cubit.selectedYieldTimeframe).thenReturn(YieldTimeFrame.day); await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key("yield-card-24h"))); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(const Key("deposit-settings-button"))); await tester.pumpAndSettle(); @@ -2091,12 +2080,12 @@ void main() { zGoldenTest( "When loading the screen, and the network in the path param is different from the selected one, it should switch the network", (tester) async { - when(() => navigator.getParam(any())).thenAnswer((_) => Networks.scroll.name); + when(() => navigator.getParam(any())).thenAnswer((_) => AppNetworks.scroll.name); await tester.runAsync(() async => await tester.pumpDeviceBuilder(await goldenBuilder())); await tester.pumpAndSettle(); - verify(() => appCubit.updateAppNetwork(Networks.scroll)).called(1); + verify(() => appCubit.updateAppNetwork(AppNetworks.scroll)).called(1); }, ); 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 2ec2f5b..904de8f 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 3659b38..6161c04 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 30979bd..34ce737 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 81a6d12..7614039 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 4541ae4..3df86de 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 0ddf2ca..56eabef 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 cca65de..653c1fb 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 042ff90..49ca770 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 68dcca2..575cddb 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 6149346..3b331ac 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 0b22fa7..46ed296 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 24c990d..a909a39 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 1a464c8..7a4da94 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 d0f5289..309119d 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 97bef8d..d07a0cf 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 2f4e0e1..e834e52 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 bfb76b8..5d4822b 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 f4adbf3..4341cb3 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 366f286..9f994b2 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 23bf380..8896a87 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 8a0a791..01e7fcb 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 0ccb64a..95ef2ab 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 af48c76..658deaf 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 20a2292..782df4d 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 004e7d2..0986374 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 15b318b..6fb02e2 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 3f25d78..4683ea4 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 7076c77..bf0e2c7 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 660d3e0..4ea6e5b 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 20a2292..782df4d 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 2f4e0e1..e834e52 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 aecc9df..dcae01e 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_max_price_less_than_min_price.png b/test/app/create/deposit/goldens/deposit_page_max_price_less_than_min_price.png index bea03fe..a8c13cc 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 617d510..61d825e 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 30979bd..34ce737 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 2c1ddae..933ae3d 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 e4d56b5..a6b9824 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 30979bd..34ce737 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 742e47b..dbd9e62 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 2a10712..5828808 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 4523aa2..01b4f8e 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 30979bd..34ce737 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 2cab092..9a27744 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 1baa348..78ff412 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 798bdd2..80ca84d 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 5cd0d43..3388211 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 4976314..c322acf 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 d73a3bf..f0bfd9a 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 c8c4002..4ce269e 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 c8c4002..4ce269e 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_preview_modal.png b/test/app/create/deposit/goldens/deposit_page_preview_modal.png index 4204ddc..21d2cec 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 1b2f206..e44b71c 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 8984929..3d0d898 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 411773a..48308b8 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 1ddd9d6..0743e50 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 b99b414..086db15 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_select_yield_scroll.png b/test/app/create/deposit/goldens/deposit_page_select_yield_scroll.png index 22c96e5..87d0acb 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_select_yield_scroll.png and b/test/app/create/deposit/goldens/deposit_page_select_yield_scroll.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_selected_yield_stream.png b/test/app/create/deposit/goldens/deposit_page_selected_yield_stream.png index b940c6d..0a04faf 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_selected_yield_stream.png and b/test/app/create/deposit/goldens/deposit_page_selected_yield_stream.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 5009443..8b6285c 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/goldens/deposit_page_success_filtered_by_min_liquidity.png b/test/app/create/deposit/goldens/deposit_page_success_filtered_by_min_liquidity.png index 4b7e3b1..7b3bed1 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_success_filtered_by_min_liquidity.png and b/test/app/create/deposit/goldens/deposit_page_success_filtered_by_min_liquidity.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_success_filtered_by_min_liquidity_local_filter_set.png b/test/app/create/deposit/goldens/deposit_page_success_filtered_by_min_liquidity_local_filter_set.png index 57bb29e..3de9b1a 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_success_filtered_by_min_liquidity_local_filter_set.png and b/test/app/create/deposit/goldens/deposit_page_success_filtered_by_min_liquidity_local_filter_set.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_success_mobile.png b/test/app/create/deposit/goldens/deposit_page_success_mobile.png index b1449bb..d4c4086 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_success_mobile.png and b/test/app/create/deposit/goldens/deposit_page_success_mobile.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_success_not_filtered_by_min_liquidity.png b/test/app/create/deposit/goldens/deposit_page_success_not_filtered_by_min_liquidity.png index c40cbfb..da241c5 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_success_not_filtered_by_min_liquidity.png and b/test/app/create/deposit/goldens/deposit_page_success_not_filtered_by_min_liquidity.png differ diff --git a/test/app/create/deposit/goldens/deposit_page_timeframe_tooltip.png b/test/app/create/deposit/goldens/deposit_page_timeframe_tooltip.png index 5e2e5d4..567291f 100644 Binary files a/test/app/create/deposit/goldens/deposit_page_timeframe_tooltip.png and b/test/app/create/deposit/goldens/deposit_page_timeframe_tooltip.png differ 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 c253b5d..9a8bd42 100644 --- a/test/app/create/deposit/widgets/deposit_success_modal_test.dart +++ b/test/app/create/deposit/widgets/deposit_success_modal_test.dart @@ -120,9 +120,9 @@ void main() { """When passing depositedWithNative to true, the modal should use the native token symbol in the description if the token0 or token1 are wrapped natives""", (tester) async { final wrappedNativeYield = YieldDto.fixture().copyWith( - network: Networks.sepolia, - token0: Networks.sepolia.wrappedNative, - token1: Networks.sepolia.wrappedNative, + chainId: AppNetworks.sepolia.chainId, + token0: AppNetworks.sepolia.wrappedNative, + token1: AppNetworks.sepolia.wrappedNative, ); await tester.pumpDeviceBuilder( @@ -147,9 +147,9 @@ void main() { """When passing depositedWithNative to true, the modal should use the native token images in the tokenavatars (if the token0 or token1 are wrapped natives)""", (tester) async { final wrappedNativeYield = YieldDto.fixture().copyWith( - network: Networks.sepolia, - token0: Networks.sepolia.wrappedNative, - token1: Networks.sepolia.wrappedNative, + chainId: AppNetworks.sepolia.chainId, + token0: AppNetworks.sepolia.wrappedNative, + token1: AppNetworks.sepolia.wrappedNative, ); await tester.pumpDeviceBuilder( 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 8ac01b5..a89c361 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 8ac01b5..a89c361 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 493e613..d9caebd 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 dc96401..eb6aad1 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 3f6d63c..9bee408 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_current_price.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_current_price.png index de51577..5e08f4c 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 037342c..fb881b1 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 de51577..5e08f4c 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 2a70594..de6de2f 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_with_native_token.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_deposit_with_native_token.png index 20a92d0..ebb24fe 100644 Binary files a/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_deposit_with_native_token.png and b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_deposit_with_native_token.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 28fd38e..e40a748 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 0ecf303..ecc587b 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 64e3926..272f6dd 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 609c08d..053ef89 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 ae0696a..133fd16 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 606a9a2..22b7fed 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 ff2e56a..56529cc 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 c6c1885..cd9ecac 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 29ad279..e9fb310 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 7e21a1e..185722f 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 b157a86..6dc8749 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 1fc188e..b7e8576 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 7e21a1e..185722f 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 037342c..fb881b1 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 fc92f50..148a964 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 230c6ba..1cb8b2b 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 c6ff67d..e033411 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_transaction_error.png b/test/app/create/deposit/widgets/preview_deposit_modal/goldens/preview_deposit_modal_transaction_error.png index 9cca922..b40719b 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 de51577..5e08f4c 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 51fbe44..a1a0243 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 8e89dd2..012bc49 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 99a27a5..d5191c1 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 @@ -259,8 +259,13 @@ void main() { and then emit the initial state with the allowance values""", () async { final customYield = YieldDto.fixture().copyWith( - token0: TokenDto.fixture().copyWith(address: "Token 0 Address"), - token1: TokenDto.fixture().copyWith(address: "Token 1 Address"), + 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", + }), ); sut = PreviewDepositModalCubit( @@ -279,11 +284,13 @@ void main() { final token0Allowance = BigInt.from(12345); final token1Allowance = BigInt.from(54321); - when(() => erc20.fromRpcProvider(contractAddress: customYield.token0.address, rpcUrl: any(named: "rpcUrl"))) - .thenReturn(token0Contract); + when(() => erc20.fromRpcProvider( + contractAddress: customYield.token0.addresses[customYield.network.chainId]!, + rpcUrl: any(named: "rpcUrl"))).thenReturn(token0Contract); - when(() => erc20.fromRpcProvider(contractAddress: customYield.token1.address, rpcUrl: any(named: "rpcUrl"))) - .thenReturn(token1Contract); + when(() => erc20.fromRpcProvider( + contractAddress: customYield.token1.addresses[customYield.network.chainId]!, + rpcUrl: any(named: "rpcUrl"))).thenReturn(token1Contract); when(() => token0Contract.allowance(owner: any(named: "owner"), spender: any(named: "spender"))) .thenAnswer((_) async => token0Allowance); @@ -318,8 +325,8 @@ void main() { network is not the same as the token network, it should ask to switch the network""", () async { - const yieldNetwork = Networks.sepolia; - final customYield = YieldDto.fixture().copyWith(network: yieldNetwork); + const yieldNetwork = AppNetworks.sepolia; + final customYield = YieldDto.fixture().copyWith(chainId: yieldNetwork.chainId); sut = PreviewDepositModalCubit( navigatorKey: GlobalKey(), @@ -333,7 +340,7 @@ void main() { zupAnalytics: zupAnalytics); when(() => wallet.switchOrAddNetwork(any())).thenAnswer((_) async {}); - when(() => wallet.connectedNetwork).thenAnswer((_) async => Networks.mainnet.chainInfo); + when(() => wallet.connectedNetwork).thenAnswer((_) async => AppNetworks.mainnet.chainInfo); await sut.approveToken(currentYield.token0, BigInt.from(32761)); @@ -346,8 +353,8 @@ void main() { network is the same as the token network, it should not ask to switch the network""", () async { - const yieldNetwork = Networks.sepolia; - final customYield = YieldDto.fixture().copyWith(network: yieldNetwork); + const yieldNetwork = AppNetworks.sepolia; + final customYield = YieldDto.fixture().copyWith(chainId: yieldNetwork.chainId); sut = PreviewDepositModalCubit( navigatorKey: GlobalKey(), @@ -386,8 +393,8 @@ void main() { await sut.approveToken(token, tokenAmount); - verify(() => erc20.fromSigner(contractAddress: token.address, signer: signer)).called(1); - verify(() => erc20Impl.approve(spender: currentYield.protocol.positionManager, value: tokenAmount)).called(1); + verify(() => erc20.fromSigner(contractAddress: token.addresses[currentYield.chainId]!, signer: signer)).called(1); + verify(() => erc20Impl.approve(spender: currentYield.positionManagerAddress, value: tokenAmount)).called(1); }, ); @@ -452,8 +459,9 @@ void main() { final token0Erc20Impl = Erc20ImplMock(); - when(() => erc20.fromRpcProvider(contractAddress: currentYield.token0.address, rpcUrl: any(named: "rpcUrl"))) - .thenReturn(token0Erc20Impl); + when(() => erc20.fromRpcProvider( + contractAddress: currentYield.token0.addresses[currentYield.chainId]!, + rpcUrl: any(named: "rpcUrl"))).thenReturn(token0Erc20Impl); when(() => token0Erc20Impl.allowance(owner: any(named: "owner"), spender: any(named: "spender"))).thenAnswer( (_) async => expectedToken0Allowance, @@ -478,8 +486,9 @@ void main() { final token1Erc20Impl = Erc20ImplMock(); - when(() => erc20.fromRpcProvider(contractAddress: currentYield.token1.address, rpcUrl: any(named: "rpcUrl"))) - .thenReturn(token1Erc20Impl); + when(() => erc20.fromRpcProvider( + contractAddress: currentYield.token1.addresses[currentYield.chainId]!, + rpcUrl: any(named: "rpcUrl"))).thenReturn(token1Erc20Impl); when(() => token1Erc20Impl.allowance(owner: any(named: "owner"), spender: any(named: "spender"))).thenAnswer( (_) async => expectedToken1Allowance, @@ -505,8 +514,9 @@ void main() { final token0Allowance = BigInt.from(12345); final token0Erc20Impl = Erc20ImplMock(); - when(() => erc20.fromRpcProvider(contractAddress: currentYield.token0.address, rpcUrl: any(named: "rpcUrl"))) - .thenReturn(token0Erc20Impl); + when(() => erc20.fromRpcProvider( + contractAddress: currentYield.token0.addresses[currentYield.chainId]!, + rpcUrl: any(named: "rpcUrl"))).thenReturn(token0Erc20Impl); when(() => token0Erc20Impl.allowance(owner: any(named: "owner"), spender: any(named: "spender"))).thenAnswer( (_) async => token0Allowance, @@ -536,8 +546,9 @@ void main() { final token1Allowance = BigInt.from(12345); final token1Erc20Impl = Erc20ImplMock(); - when(() => erc20.fromRpcProvider(contractAddress: currentYield.token1.address, rpcUrl: any(named: "rpcUrl"))) - .thenReturn(token1Erc20Impl); + when(() => erc20.fromRpcProvider( + contractAddress: currentYield.token1.addresses[currentYield.chainId]!, + rpcUrl: any(named: "rpcUrl"))).thenReturn(token1Erc20Impl); when(() => token1Erc20Impl.allowance(owner: any(named: "owner"), spender: any(named: "spender"))).thenAnswer( (_) async => token1Allowance, @@ -662,8 +673,8 @@ void main() { """When calling `deposit` and the signer connected network is different from the yield network, it should ask the user to switch network""", () async { - final connectedNetwork = Networks.mainnet.chainInfo; - final yieldNetwork = Networks.sepolia.chainInfo; + final connectedNetwork = AppNetworks.mainnet.chainInfo; + final yieldNetwork = AppNetworks.sepolia.chainInfo; when(() => wallet.connectedNetwork).thenAnswer((_) async => connectedNetwork); @@ -688,8 +699,8 @@ void main() { the same from the yield network, it should not ask the user to switch network""", () async { - final connectedNetwork = Networks.sepolia.chainInfo; - final yieldNetwork = Networks.sepolia.chainInfo; + final connectedNetwork = AppNetworks.sepolia.chainInfo; + final yieldNetwork = AppNetworks.sepolia.chainInfo; when(() => wallet.connectedNetwork).thenAnswer((_) async => connectedNetwork); @@ -733,8 +744,8 @@ void main() { expects: (item) { expect(item.amount0Desired, token0Amount); expect(item.amount1Desired, token1Amount); - expect(item.token0, currentYield.token0.address); - expect(item.token1, currentYield.token1.address); + expect(item.token0, currentYield.token0.addresses[currentYield.network.chainId]!); + expect(item.token1, currentYield.token1.addresses[currentYield.network.chainId]!); }, ), ), @@ -1230,7 +1241,7 @@ void main() { params: any( named: "params", that: ExpectedMatcher( - expects: (item) => expect(item.token0, currentYield.token0.address), + expects: (item) => expect(item.token0, currentYield.token0.addresses[currentYield.network.chainId]!), ), ), ), @@ -1257,7 +1268,7 @@ void main() { params: any( named: "params", that: ExpectedMatcher( - expects: (item) => expect(item.token1, currentYield.token1.address), + expects: (item) => expect(item.token1, currentYield.token1.addresses[currentYield.network.chainId]!), ), ), ), 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 020c8ed..296fcd4 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 @@ -128,6 +128,7 @@ void main() { content: BlocProvider.value( value: cubit, child: PreviewDepositModal( + yieldTimeFrame: YieldTimeFrame.day, depositWithNativeToken: depositWithNativeToken, deadline: deadline, maxSlippage: slippage, @@ -199,7 +200,7 @@ void main() { it should open the transaction in the yield network's explorer""", (tester) async { const txId = "0xtxID"; - const yieldNetwork = Networks.sepolia; + const yieldNetwork = AppNetworks.sepolia; when(() => cubit.state).thenReturn( const PreviewDepositModalState.waitingTransaction(txId: "txID", type: WaitingTransactionType.deposit)); @@ -209,7 +210,7 @@ void main() { ); await tester.pumpDeviceBuilder( - await goldenBuilder(customYield: YieldDto.fixture().copyWith(network: yieldNetwork)), + await goldenBuilder(customYield: YieldDto.fixture().copyWith(chainId: yieldNetwork.chainId)), wrapper: GoldenConfig.localizationsWrapper(), ); await tester.pumpAndSettle(); @@ -299,8 +300,12 @@ void main() { await goldenBuilder( depositWithNativeToken: true, customYield: currentYield.copyWith( - token0: TokenDto.fixture().copyWith(address: currentYield.network.wrappedNative.address), - token1: TokenDto.fixture().copyWith(address: "0x21"), + token0: TokenDto.fixture().copyWith(addresses: { + currentYield.network.chainId: currentYield.network.wrappedNative.addresses[currentYield.network.chainId] + }), + token1: TokenDto.fixture().copyWith(addresses: { + currentYield.network.chainId: currentYield.network.wrappedNative.addresses[currentYield.network.chainId] + }), ), ), wrapper: GoldenConfig.localizationsWrapper()); @@ -934,6 +939,7 @@ void main() { Builder(builder: (context) { WidgetsBinding.instance.addPostFrameCallback((_) async { PreviewDepositModal( + yieldTimeFrame: YieldTimeFrame.day, depositWithNativeToken: false, currentYield: currentYield, isReversed: true, @@ -967,6 +973,7 @@ void main() { Builder(builder: (context) { WidgetsBinding.instance.addPostFrameCallback((_) async { PreviewDepositModal( + yieldTimeFrame: YieldTimeFrame.day, depositWithNativeToken: false, currentYield: currentYield, isReversed: true, 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 479a289..fff6c63 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 @@ -38,14 +38,14 @@ void main() { await inject.reset(); }); - Future goldenBuilder({ - Key? key, - TextEditingController? controller, - Networks network = Networks.sepolia, - Function(double)? onInput, - TokenDto? token, - String? disabledText, - }) async => + Future goldenBuilder( + {Key? key, + TextEditingController? controller, + AppNetworks network = AppNetworks.sepolia, + Function(double)? onInput, + TokenDto? token, + String? disabledText, + bool isNative = false}) async => await goldenDeviceBuilder( Center( child: Column( @@ -55,6 +55,7 @@ void main() { width: 500, child: TokenAmountInputCard( key: key, + isNative: isNative, controller: controller ?? TextEditingController(), network: network, onInput: (value) => onInput?.call(value), @@ -201,7 +202,10 @@ void main() { (tester) async { const key = Key("token-amount-card"); const newTokenAddress = "0xN3W_T0K3N"; - final newToken = TokenDto.fixture().copyWith(address: newTokenAddress, symbol: "NEW_TOKEN"); + final newToken = TokenDto.fixture().copyWith( + addresses: {AppNetworks.sepolia.chainId: newTokenAddress}, + symbol: "NEW_TOKEN", + ); await tester.pumpDeviceBuilder(await goldenBuilder(key: key)); await tester.pumpDeviceBuilder(await goldenBuilder(key: key, token: newToken)); @@ -210,6 +214,69 @@ void main() { }, ); + zGoldenTest( + "When updating the widget from a native token, for a different native token, it should update the token in the cubit and get the balance again", + (tester) async { + const key = Key("token-amount-card"); + + const oldTokenNetwork = AppNetworks.scroll; + const newTokenNetwork = AppNetworks.sepolia; + + final oldTokenAddress = AppNetworks.scroll.wrappedNativeTokenAddress; + final oldToken = TokenDto.fixture().copyWith( + addresses: {AppNetworks.scroll.chainId: oldTokenAddress}, + symbol: "OLD_TOKEN", + ); + + final newTokenAddress = AppNetworks.sepolia.wrappedNativeTokenAddress; + final newToken = TokenDto.fixture().copyWith( + addresses: {AppNetworks.sepolia.chainId: newTokenAddress}, + symbol: "NEW_TOKEN", + ); + + await tester.pumpDeviceBuilder( + await goldenBuilder(key: key, token: oldToken, isNative: true, network: oldTokenNetwork), + ); + await tester.pumpDeviceBuilder( + await goldenBuilder(key: key, token: newToken, isNative: true, network: newTokenNetwork), + ); + + verify(() => wallet.nativeOrTokenBalance(EthereumConstants.zeroAddress, rpcUrl: newTokenNetwork.rpcUrl)) + .called(1); + }, + ); + + zGoldenTest( + "When updating the widget from a non-native token, for a different non-native token, it should update the token in the cubit and get the balance again", + (tester) async { + const key = Key("token-amount-card"); + + const oldTokenNetwork = AppNetworks.scroll; + const newTokenNetwork = AppNetworks.sepolia; + + final oldTokenAddress = AppNetworks.scroll.wrappedNativeTokenAddress; + final oldToken = TokenDto.fixture().copyWith( + addresses: {AppNetworks.scroll.chainId: oldTokenAddress}, + symbol: "OLD_TOKEN", + ); + + final newTokenAddress = AppNetworks.sepolia.wrappedNativeTokenAddress; + final newToken = TokenDto.fixture().copyWith( + addresses: {AppNetworks.sepolia.chainId: newTokenAddress}, + symbol: "NEW_TOKEN", + ); + + await tester.pumpDeviceBuilder( + await goldenBuilder(key: key, token: oldToken, isNative: false, network: oldTokenNetwork), + ); + await tester.pumpDeviceBuilder( + await goldenBuilder(key: key, token: newToken, isNative: false, network: newTokenNetwork), + ); + + verify(() => wallet.nativeOrTokenBalance(newTokenAddress, rpcUrl: newTokenNetwork.rpcUrl)).called(1); + }, + ); + zGoldenTest( """When there's a large number typed, it should not hard clip it in the left border, but instead do a soft clip with a gradient""", 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 fd982ac..9995855 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 @@ -19,6 +19,10 @@ void main() { setUp(() async { wallet = WalletMock(); signer = SignerMock(); + + when(() => wallet.signer).thenReturn(signer); + when(() => wallet.signerStream).thenAnswer((_) => Stream.value(signer)); + when(() => signer.address).thenAnswer((_) => Future.value("0xS0M3_4ddr355")); }); tearDown(() async { @@ -46,7 +50,7 @@ void main() { final sut0 = TokenAmountCardUserBalanceCubit( wallet, tokenAddress, - Networks.sepolia, + AppNetworks.sepolia, ZupSingletonCache.shared, () {}, ); @@ -78,7 +82,7 @@ void main() { final sut0 = TokenAmountCardUserBalanceCubit( wallet, tokenAddress, - Networks.sepolia, + AppNetworks.sepolia, ZupSingletonCache.shared, () {}, ); @@ -103,7 +107,7 @@ void main() { final sut0 = TokenAmountCardUserBalanceCubit( wallet, tokenAddress, - Networks.sepolia, + AppNetworks.sepolia, ZupSingletonCache.shared, () {}, ); @@ -127,7 +131,7 @@ void main() { final sut0 = TokenAmountCardUserBalanceCubit( wallet, tokenAddress, - Networks.sepolia, + AppNetworks.sepolia, ZupSingletonCache.shared, () {}, ); @@ -153,7 +157,7 @@ void main() { final sut0 = TokenAmountCardUserBalanceCubit( wallet, tokenAddress, - Networks.sepolia, + AppNetworks.sepolia, ZupSingletonCache.shared, () {}, ); @@ -189,7 +193,7 @@ void main() { final sut0 = TokenAmountCardUserBalanceCubit( wallet, tokenAddress, - Networks.sepolia, + AppNetworks.sepolia, ZupSingletonCache.shared, () {}, ); @@ -227,7 +231,7 @@ void main() { final sut0 = TokenAmountCardUserBalanceCubit( wallet, tokenAddress, - Networks.sepolia, + AppNetworks.sepolia, ZupSingletonCache.shared, () {}, ); @@ -259,14 +263,14 @@ void main() { final sut0 = TokenAmountCardUserBalanceCubit( wallet, tokenAddress, - Networks.sepolia, + AppNetworks.sepolia, ZupSingletonCache.shared, () {}, ); await Future.delayed(const Duration(seconds: 0)); - await sut0.updateToken(newTokenAddress); + await sut0.updateTokenAndNetwork(newTokenAddress, AppNetworks.sepolia, asNativeToken: false); verify(() => wallet.nativeOrTokenBalance(newTokenAddress, rpcUrl: any(named: "rpcUrl"))).called(1); }); @@ -282,13 +286,33 @@ void main() { final sut0 = TokenAmountCardUserBalanceCubit( wallet, tokenAddress, - Networks.sepolia, + AppNetworks.sepolia, ZupSingletonCache.shared, () {}, ); - await sut0.updateToken(newTokenAddress); + await sut0.updateTokenAndNetwork(newTokenAddress, AppNetworks.sepolia, asNativeToken: false); verifyNever(() => wallet.nativeOrTokenBalance(newTokenAddress, rpcUrl: any(named: "rpcUrl"))); }); + + test( + """When calling 'updateTokenAndNetwork' with 'asNativeToken' true, + it should pass the address zero to wallet to get the native balance""", + () async { + const tokenAddress = "0x99E3CfADCD8Feecb5DdF91f88998cFfB3145F78c"; + + final sut0 = TokenAmountCardUserBalanceCubit( + wallet, + tokenAddress, + AppNetworks.sepolia, + ZupSingletonCache.shared, + () {}, + ); + + await sut0.updateTokenAndNetwork(tokenAddress, AppNetworks.sepolia, asNativeToken: true); + + verify(() => wallet.nativeOrTokenBalance(EthereumConstants.zeroAddress, rpcUrl: any(named: "rpcUrl"))).called(1); + }, + ); } diff --git a/test/app/create/goldens/create_page_initial_stage.png b/test/app/create/goldens/create_page_initial_stage.png index 5eee8c4..f4f50bf 100644 Binary files a/test/app/create/goldens/create_page_initial_stage.png and b/test/app/create/goldens/create_page_initial_stage.png differ diff --git a/test/app/create/goldens/create_page_select_tokens_stage_default_a_token.png b/test/app/create/goldens/create_page_select_tokens_stage_default_a_token.png index 5eee8c4..f4f50bf 100644 Binary files a/test/app/create/goldens/create_page_select_tokens_stage_default_a_token.png and b/test/app/create/goldens/create_page_select_tokens_stage_default_a_token.png differ diff --git a/test/app/create/goldens/create_page_select_tokens_stage_mobile.png b/test/app/create/goldens/create_page_select_tokens_stage_mobile.png index 786a48e..6563383 100644 Binary files a/test/app/create/goldens/create_page_select_tokens_stage_mobile.png and b/test/app/create/goldens/create_page_select_tokens_stage_mobile.png differ diff --git a/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_add_badge.png b/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_add_badge.png index 0a47498..6a3ac07 100644 Binary files a/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_add_badge.png and b/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_add_badge.png differ diff --git a/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_default.png b/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_default.png index 5c44858..d135433 100644 Binary files a/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_default.png and b/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_default.png differ diff --git a/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_not_default.png b/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_not_default.png index 0a47498..6a3ac07 100644 Binary files a/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_not_default.png and b/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_not_default.png differ 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 5495ce1..09b6f2f 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_pool_search_settings_remove_badge.png b/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_remove_badge.png index 5c44858..d135433 100644 Binary files a/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_remove_badge.png and b/test/app/create/goldens/create_page_select_tokens_stage_pool_search_settings_remove_badge.png differ diff --git a/test/app/create/goldens/create_page_select_tokens_stage_reset_tokens_from_network.png b/test/app/create/goldens/create_page_select_tokens_stage_reset_tokens_from_network.png index 0a47498..6a3ac07 100644 Binary files a/test/app/create/goldens/create_page_select_tokens_stage_reset_tokens_from_network.png and b/test/app/create/goldens/create_page_select_tokens_stage_reset_tokens_from_network.png differ diff --git a/test/core/dto/yield_dto_test.dart b/test/core/dto/yield_dto_test.dart index f84073d..be677c9 100644 --- a/test/core/dto/yield_dto_test.dart +++ b/test/core/dto/yield_dto_test.dart @@ -1,5 +1,4 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:web3kit/web3kit.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'; @@ -22,7 +21,14 @@ void main() { test("""When calling `maybeNativeToken1` with `permitNative` true, and a token 1 that is not the wrapped native address, it should return the yield token1""", () { - final sut = YieldDto.fixture().copyWith(token1: const TokenDto(address: "0x123")); + final chainId = AppNetworks.mainnet.chainId; + + final sut = YieldDto.fixture().copyWith( + chainId: chainId, + token1: TokenDto( + addresses: {chainId: "0x123"}, + ), + ); final token = sut.maybeNativeToken1(permitNative: true); expect(token, sut.token1); @@ -31,7 +37,14 @@ void main() { test("""When calling `maybeNativeToken0` with `permitNative` true, and a token 0 that is not the wrapped native address, it should return the yield token0""", () { - final sut = YieldDto.fixture().copyWith(token0: const TokenDto(address: "0x123")); + final chainId = AppNetworks.mainnet.chainId; + + final sut = YieldDto.fixture().copyWith( + chainId: chainId, + token0: TokenDto( + addresses: {chainId: "0x123"}, + ), + ); final token = sut.maybeNativeToken0(permitNative: true); expect(token, sut.token0); @@ -40,10 +53,10 @@ void main() { test("""When calling `maybeNativeToken1` with `permitNative` true, and a token 1 that is the wrapped native address, it should return the native token for the yield network""", () { - const network = Networks.sepolia; + const network = AppNetworks.sepolia; final sut = YieldDto.fixture().copyWith( - token1: TokenDto(address: network.wrappedNativeTokenAddress), - network: network, + token1: TokenDto(addresses: {network.chainId: network.wrappedNativeTokenAddress}), + chainId: network.chainId, ); final token = sut.maybeNativeToken1(permitNative: true); @@ -51,7 +64,7 @@ void main() { expect( token, TokenDto( - address: EthereumConstants.zeroAddress, + addresses: {network.chainId: network.wrappedNativeTokenAddress}, decimals: network.chainInfo.nativeCurrency!.decimals, logoUrl: network.chainInfo.nativeCurrency!.logoUrl, symbol: network.chainInfo.nativeCurrency!.symbol, @@ -62,10 +75,11 @@ void main() { test("""When calling `maybeNativeToken0` with `permitNative` true, and a token 0 that is the wrapped native address, it should return the native token for the yield network""", () { - const network = Networks.sepolia; + const network = AppNetworks.sepolia; + final sut = YieldDto.fixture().copyWith( - token0: TokenDto(address: network.wrappedNativeTokenAddress), - network: network, + token0: TokenDto(addresses: {network.chainId: network.wrappedNativeTokenAddress}), + chainId: network.chainId, ); final token = sut.maybeNativeToken0(permitNative: true); @@ -73,7 +87,7 @@ void main() { expect( token, TokenDto( - address: EthereumConstants.zeroAddress, + addresses: {network.chainId: network.wrappedNativeTokenAddress}, decimals: network.chainInfo.nativeCurrency!.decimals, logoUrl: network.chainInfo.nativeCurrency!.logoUrl, symbol: network.chainInfo.nativeCurrency!.symbol, diff --git a/test/core/enums/networks_test.dart b/test/core/enums/networks_test.dart index 9bbf143..2d7b151 100644 --- a/test/core/enums/networks_test.dart +++ b/test/core/enums/networks_test.dart @@ -3,7 +3,6 @@ import 'package:golden_toolkit/golden_toolkit.dart'; import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; import 'package:web3kit/core/dtos/chain_info.dart'; import 'package:web3kit/core/enums/native_currencies.dart'; -import 'package:web3kit/core/ethereum_constants.dart'; import 'package:zup_app/core/dtos/token_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; @@ -19,40 +18,40 @@ void main() { }); test("When calling 'fromValue' it should get a network from a string value", () { - expect(Networks.fromValue("sepolia"), Networks.sepolia); - expect(Networks.fromValue("mainnet"), Networks.mainnet); - expect(Networks.fromValue("scroll"), Networks.scroll); + expect(AppNetworks.fromValue("sepolia"), AppNetworks.sepolia); + expect(AppNetworks.fromValue("mainnet"), AppNetworks.mainnet); + expect(AppNetworks.fromValue("scroll"), AppNetworks.scroll); }); test("Label extension should match for all networks", () { - expect(Networks.sepolia.label, "Sepolia", reason: "Sepolia Label should match"); - expect(Networks.mainnet.label, "Ethereum", reason: "Ethereum Label should match"); - expect(Networks.scroll.label, "Scroll", reason: "Scroll Label should match"); + expect(AppNetworks.sepolia.label, "Sepolia", reason: "Sepolia Label should match"); + expect(AppNetworks.mainnet.label, "Ethereum", reason: "Ethereum Label should match"); + expect(AppNetworks.scroll.label, "Scroll", reason: "Scroll Label should match"); }); - test("`testnets` method should return all testnets in the enum", () { - expect(Networks.testnets, [Networks.sepolia]); + test("`testnets` method should return all testnets in the enum, excluding the 'all networks'", () { + expect(AppNetworks.testnets, [AppNetworks.sepolia]); }); - test("`testnets` method should return all testnets in the enum", () { - expect(Networks.mainnets, [Networks.mainnet, Networks.scroll]); + test("`mainnets` method should return all mainnets in the enum, including the 'all networks'", () { + expect(AppNetworks.mainnets, [AppNetworks.allNetworks, AppNetworks.mainnet, AppNetworks.scroll]); }); test("`isTestnet` method should return true for sepolia", () { - expect(Networks.sepolia.isTestnet, true); + expect(AppNetworks.sepolia.isTestnet, true); }); test("`isTestnet` method should return false for mainnet", () { - expect(Networks.mainnet.isTestnet, false); + expect(AppNetworks.mainnet.isTestnet, false); }); test("`isTestnet` method should return false for Scroll", () { - expect(Networks.scroll.isTestnet, false); + expect(AppNetworks.scroll.isTestnet, false); }); test("Chain info extension should match for all networks", () { expect( - Networks.sepolia.chainInfo, + AppNetworks.sepolia.chainInfo, ChainInfo( hexChainId: "0xaa36a7", chainName: "Sepolia", @@ -64,7 +63,7 @@ void main() { ); expect( - Networks.mainnet.chainInfo, + AppNetworks.mainnet.chainInfo, ChainInfo( hexChainId: "0x1", chainName: "Ethereum", @@ -75,7 +74,7 @@ void main() { ); expect( - Networks.scroll.chainInfo, + AppNetworks.scroll.chainInfo, ChainInfo( hexChainId: "0x82750", chainName: "Scroll", @@ -89,19 +88,19 @@ void main() { test("wrapped native token address should match for all networks", () { expect( - Networks.sepolia.wrappedNativeTokenAddress, + AppNetworks.sepolia.wrappedNativeTokenAddress, "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", reason: "Sepolia wrapped native token address should match", ); expect( - Networks.mainnet.wrappedNativeTokenAddress, + AppNetworks.mainnet.wrappedNativeTokenAddress, "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", reason: "Ethereum wrapped native token address should match", ); expect( - Networks.scroll.wrappedNativeTokenAddress, + AppNetworks.scroll.wrappedNativeTokenAddress, "0x5300000000000000000000000000000000000004", reason: "Scroll wrapped native token address should match", ); @@ -109,9 +108,11 @@ void main() { test("wrapped native token should match for all networks", () { expect( - Networks.sepolia.wrappedNative, - const TokenDto( - address: "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + AppNetworks.sepolia.wrappedNative, + TokenDto( + addresses: { + AppNetworks.sepolia.chainId: "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + }, name: "Wrapped Ether", decimals: 18, symbol: "WETH", @@ -121,9 +122,11 @@ void main() { ); expect( - Networks.mainnet.wrappedNative, - const TokenDto( - address: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + AppNetworks.mainnet.wrappedNative, + TokenDto( + addresses: { + AppNetworks.mainnet.chainId: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + }, name: "Wrapped Ether", decimals: 18, symbol: "WETH", @@ -133,9 +136,11 @@ void main() { ); expect( - Networks.scroll.wrappedNative, - const TokenDto( - address: "0x5300000000000000000000000000000000000004", + AppNetworks.scroll.wrappedNative, + TokenDto( + addresses: { + AppNetworks.scroll.chainId: "0x5300000000000000000000000000000000000004", + }, name: "Wrapped Ether", decimals: 18, symbol: "WETH", @@ -148,19 +153,19 @@ void main() { test("RpcUrl extension should return the correct rpc url", () { expect( - Networks.sepolia.rpcUrl, + AppNetworks.sepolia.rpcUrl, "https://ethereum-sepolia-rpc.publicnode.com", reason: "Sepolia rpc url should match", ); expect( - Networks.mainnet.rpcUrl, + AppNetworks.mainnet.rpcUrl, "https://ethereum-rpc.publicnode.com", reason: "Ethereum rpc url should match", ); expect( - Networks.scroll.rpcUrl, + AppNetworks.scroll.rpcUrl, "https://scroll-rpc.publicnode.com", reason: "Scroll rpc url should match", ); @@ -169,7 +174,9 @@ void main() { test("openTx should open the correct url for each network", () async { const txHash = "0x1271892718912u198haisghsg7223617"; - for (final network in Networks.values) { + for (final network in AppNetworks.values) { + if (network.isAllNetworks) continue; + await network.openTx(txHash); expect( @@ -182,9 +189,9 @@ void main() { test("'nativeCurrency' should return the correct currency for sepolia network", () { expect( - Networks.sepolia.nativeCurrencyTokenDto, + AppNetworks.sepolia.nativeCurrencyTokenDto, TokenDto( - address: EthereumConstants.zeroAddress, + addresses: {}, name: NativeCurrencies.eth.currencyInfo.name, decimals: NativeCurrencies.eth.currencyInfo.decimals, symbol: NativeCurrencies.eth.currencyInfo.symbol, @@ -196,9 +203,9 @@ void main() { test("'nativeCurrency' should return the correct currency for ethereum network", () { expect( - Networks.mainnet.nativeCurrencyTokenDto, + AppNetworks.mainnet.nativeCurrencyTokenDto, TokenDto( - address: EthereumConstants.zeroAddress, + addresses: {}, name: NativeCurrencies.eth.currencyInfo.name, decimals: NativeCurrencies.eth.currencyInfo.decimals, symbol: NativeCurrencies.eth.currencyInfo.symbol, @@ -210,9 +217,9 @@ void main() { test("'nativeCurrency' should return the correct currency for scroll network", () { expect( - Networks.scroll.nativeCurrencyTokenDto, + AppNetworks.scroll.nativeCurrencyTokenDto, TokenDto( - address: EthereumConstants.zeroAddress, + addresses: {}, name: NativeCurrencies.eth.currencyInfo.name, decimals: NativeCurrencies.eth.currencyInfo.decimals, symbol: NativeCurrencies.eth.currencyInfo.symbol, @@ -222,16 +229,44 @@ void main() { ); }); + test("'fromChainId' should return the correct network from the chain id", () { + for (final network in AppNetworks.values) { + if (network.isAllNetworks) continue; + + expect( + AppNetworks.fromChainId(network.chainId), + network, + reason: "Network from chain id should match ${network.name}", + ); + } + }); + + test("'isAllNetworks' should return true if the network is all networks", () { + expect(AppNetworks.allNetworks.isAllNetworks, true); + }); + + test("'isAllNetworks' should return false if the network is not all networks", () { + expect(AppNetworks.scroll.isAllNetworks, false); + }); + + test("'chainId' should return the correct chain id for each network", () { + for (final network in AppNetworks.values) { + if (network.isAllNetworks) continue; + + expect(network.chainId, int.parse(network.chainInfo.hexChainId), reason: "Chain id should match ${network.name}"); + } + }); + zGoldenTest("Sepolia network icon should match", goldenFileName: "sepolia_network_icon", (tester) async { await tester.pumpDeviceBuilder(await goldenDeviceBuilder( - Networks.sepolia.icon, + AppNetworks.sepolia.icon, device: GoldenDevice.square, )); }); zGoldenTest("Ethereum network icon should match", goldenFileName: "ethereum_network_icon", (tester) async { await tester.pumpDeviceBuilder(await goldenDeviceBuilder( - Networks.mainnet.icon, + AppNetworks.mainnet.icon, device: GoldenDevice.square, )); }); diff --git a/test/core/mixins/keys_mixin_test.dart b/test/core/mixins/keys_mixin_test.dart index 7c96991..7378699 100644 --- a/test/core/mixins/keys_mixin_test.dart +++ b/test/core/mixins/keys_mixin_test.dart @@ -8,17 +8,19 @@ void main() { test("`userTokenBalanceCacheKey` should return correct key", () { const userAddress = '0xUserAddress'; const tokenAddress = '0xTokenAddress'; + const isNative = true; final key = _KeysMixinWrapper().userTokenBalanceCacheKey( userAddress: userAddress, tokenAddress: tokenAddress, + isNative: isNative, ); - expect(key, 'userTokenBalance-$userAddress-$tokenAddress'); + expect(key, 'userTokenBalance-$userAddress-$tokenAddress-native=$isNative'); }); test("`poolTickCacheKey` should return correct key", () { - const network = Networks.sepolia; + const network = AppNetworks.sepolia; const poolAddress = '0xPoolAddress'; final key = _KeysMixinWrapper().poolTickCacheKey( diff --git a/test/core/repositories/tokens_repository_test.dart b/test/core/repositories/tokens_repository_test.dart index ebd7491..beb937c 100644 --- a/test/core/repositories/tokens_repository_test.dart +++ b/test/core/repositories/tokens_repository_test.dart @@ -2,7 +2,6 @@ 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/token_list_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/repositories/tokens_repository.dart'; @@ -17,66 +16,33 @@ void main() { sut = TokensRepository(dio); }); - test("When calling `getTokenList` it should call the correct endpoint", () async { - when(() => dio.get(any(), queryParameters: any(named: "queryParameters"))).thenAnswer( - (_) async => Response( - data: TokenListDto.fixture().toJson(), - statusCode: 200, - requestOptions: RequestOptions(), - ), - ); - - await sut.getTokenList(Networks.sepolia); - - verify(() => dio.get( - "/tokens", - queryParameters: { - "network": Networks.sepolia.name, - }, - )); - }); + test("When calling `searchToken` it should call the correct endpoint", () async { + const query = "dale"; + const network = AppNetworks.sepolia; - test("When calling `getTokenList passing a user address, it should include the user address in the request", - () async { - const userAddress = "0x123"; - when(() => dio.get(any(), queryParameters: any(named: "queryParameters"))).thenAnswer( + when(() => dio.get(any(), queryParameters: any(named: "queryParameters"), cancelToken: any(named: "cancelToken"))) + .thenAnswer( (_) async => Response( - data: TokenListDto.fixture().toJson(), + data: [TokenDto.fixture().toJson()], statusCode: 200, requestOptions: RequestOptions(), ), ); - await sut.getTokenList(Networks.sepolia, userAddress: userAddress); + await sut.searchToken(query, network); verify(() => dio.get( - "/tokens", + "/tokens/search", + cancelToken: any(named: "cancelToken"), queryParameters: { - "network": Networks.sepolia.name, - "userAddress": userAddress, + "chainId": network.chainId, + "query": query, }, )); }); - test("When calling `getTokenList` it should correctly parse the response", () async { - final tokens = TokenListDto.fixture(); - - when(() => dio.get(any(), queryParameters: any(named: "queryParameters"))).thenAnswer( - (_) async => Response( - data: tokens.toJson(), - statusCode: 200, - requestOptions: RequestOptions(), - ), - ); - - final response = await sut.getTokenList(Networks.sepolia); - - expect(response, tokens); - }); - - test("When calling `searchToken` it should call the correct endpoint", () async { + test("When calling 'searchToken' and the network is all networks, it should not pass the chainId param", () async { const query = "dale"; - const network = Networks.sepolia; when(() => dio.get(any(), queryParameters: any(named: "queryParameters"), cancelToken: any(named: "cancelToken"))) .thenAnswer( @@ -87,13 +53,12 @@ void main() { ), ); - await sut.searchToken(query, network); + await sut.searchToken(query, AppNetworks.allNetworks); verify(() => dio.get( "/tokens/search", cancelToken: any(named: "cancelToken"), queryParameters: { - "network": network.name, "query": query, }, )); @@ -119,8 +84,43 @@ void main() { ), ); - final response = await sut.searchToken("query", Networks.sepolia); + final response = await sut.searchToken("query", AppNetworks.sepolia); expect(response, tokens); }); + + test("When calling `getPopularTokens` and the passed network is all networks, it should not pass the chainId param", + () async { + when(() => dio.get(any(), queryParameters: any(named: "queryParameters"))).thenAnswer( + (_) async => Response( + data: [TokenDto.fixture().toJson()], + statusCode: 200, + requestOptions: RequestOptions(), + ), + ); + + await sut.getPopularTokens(AppNetworks.allNetworks); + + verify(() => dio.get("/tokens/popular", queryParameters: {})).called(1); + }); + + test( + "When calling `getPopularTokens` and the passed network is not all networks, it should not the correct chainId param", + () async { + const network = AppNetworks.scroll; + + when(() => dio.get(any(), queryParameters: any(named: "queryParameters"))).thenAnswer( + (_) async => Response( + data: [TokenDto.fixture().toJson()], + statusCode: 200, + requestOptions: RequestOptions(), + ), + ); + + await sut.getPopularTokens(AppNetworks.scroll); + + verify(() => dio.get("/tokens/popular", queryParameters: { + "chainId": network.chainId, + })).called(1); + }); } diff --git a/test/core/repositories/yield_repository_test.dart b/test/core/repositories/yield_repository_test.dart index 8978961..ec26e06 100644 --- a/test/core/repositories/yield_repository_test.dart +++ b/test/core/repositories/yield_repository_test.dart @@ -29,22 +29,19 @@ void main() { const token0Address = "0x123"; const token1Address = "0x456"; - const network = Networks.sepolia; + const network = AppNetworks.sepolia; const minTvlUsd = 1213; - await sut.getYields( + await sut.getSingleNetworkYield( token0Address: token0Address, token1Address: token1Address, network: network, minTvlUsd: minTvlUsd, ); - verify(() => dio.get("/pools", queryParameters: { - "token0": token0Address, - "token1": token1Address, - "network": network.name, - "minTvlUsd": minTvlUsd - })).called(1); + verify(() => dio.get("/pools/search/${network.chainId}", + queryParameters: {"token0Address": token0Address, "token1Address": token1Address, "minTvlUsd": minTvlUsd})) + .called(1); }); test("When calling `getYields` it should correctly parse the response", () async { @@ -52,7 +49,7 @@ void main() { when(() => dio.get(any(), queryParameters: any(named: "queryParameters"))).thenAnswer( (_) async => Response( - data: {"bestYields": yields.toJson()}, + data: yields.toJson(), statusCode: 200, requestOptions: RequestOptions(), ), @@ -60,9 +57,9 @@ void main() { const token0Address = "0x123"; const token1Address = "0x456"; - const network = Networks.sepolia; + const network = AppNetworks.sepolia; - final response = await sut.getYields( + final response = await sut.getSingleNetworkYield( token0Address: token0Address, token1Address: token1Address, network: network, @@ -71,4 +68,55 @@ void main() { expect(response, yields); }); + + test("when calling 'getAllNetworksYield' it should call the correct endpoint with the correct params", () async { + final yields = YieldsDto.fixture(); + + when(() => dio.get(any(), queryParameters: any(named: "queryParameters"))).thenAnswer( + (_) async => Response( + data: {"bestYields": yields.toJson()}, + statusCode: 200, + requestOptions: RequestOptions(), + ), + ); + + const token0Id = "0x123"; + const token1Id = "0x456"; + const minTvlUsd = 1213; + + await sut.getAllNetworksYield( + token0InternalId: token0Id, + token1InternalId: token1Id, + minTvlUsd: minTvlUsd, + testnetMode: true, + ); + + verify(() => dio.get("/pools/search/all", + queryParameters: {"token0Id": token0Id, "token1Id": token1Id, "testnetMode": true, "minTvlUsd": minTvlUsd})) + .called(1); + }); + + test("when calling 'getAllNetworksYield' it should correctly parse the response", () async { + final yields = YieldsDto.fixture(); + + when(() => dio.get(any(), queryParameters: any(named: "queryParameters"))).thenAnswer( + (_) async => Response( + data: yields.toJson(), + statusCode: 200, + requestOptions: RequestOptions(), + ), + ); + + const token0Id = "0x123"; + const token1Id = "0x456"; + + final response = await sut.getAllNetworksYield( + token0InternalId: token0Id, + token1InternalId: token1Id, + minTvlUsd: 0, + testnetMode: true, + ); + + expect(response, yields); + }); } diff --git a/test/core/zup_analytics_test.dart b/test/core/zup_analytics_test.dart index cd19e4a..93fd5c1 100644 --- a/test/core/zup_analytics_test.dart +++ b/test/core/zup_analytics_test.dart @@ -36,8 +36,8 @@ void main() { () => firebaseAnalytics.logEvent( name: "user_deposited", parameters: { - "token0_address": "hex:${depositedYield.token0.address}", - "token1_address": "hex:${depositedYield.token1.address}", + "token0_address": "hex:${depositedYield.token0.addresses[depositedYield.network.chainId]!}", + "token1_address": "hex:${depositedYield.token1.addresses[depositedYield.network.chainId]!}", "amount0": amount0, "amount1": amount1, "network": depositedYield.network.label, diff --git a/test/widgets/app_header_test.dart b/test/widgets/app_header_test.dart index 24c56c7..c1f6748 100644 --- a/test/widgets/app_header_test.dart +++ b/test/widgets/app_header_test.dart @@ -30,7 +30,7 @@ void main() { when(() => zupNavigator.listenable).thenReturn(listenable); when(() => zupNavigator.currentRoute).thenReturn("any"); - when(() => appCubit.selectedNetwork).thenReturn(Networks.mainnet); + when(() => appCubit.selectedNetwork).thenReturn(AppNetworks.mainnet); when(() => appCubit.selectedNetworkStream).thenAnswer((_) => const Stream.empty()); when(() => appCubit.isTestnetMode).thenReturn(false); when(() => appCubit.stream).thenAnswer((_) => const Stream.empty()); diff --git a/test/widgets/goldens/yield_card_24h.png b/test/widgets/goldens/yield_card_24h.png new file mode 100644 index 0000000..85315f1 Binary files /dev/null and b/test/widgets/goldens/yield_card_24h.png differ diff --git a/test/widgets/goldens/yield_card_30d.png b/test/widgets/goldens/yield_card_30d.png new file mode 100644 index 0000000..663cf12 Binary files /dev/null and b/test/widgets/goldens/yield_card_30d.png differ diff --git a/test/widgets/goldens/yield_card_90d.png b/test/widgets/goldens/yield_card_90d.png new file mode 100644 index 0000000..695bbfe Binary files /dev/null and b/test/widgets/goldens/yield_card_90d.png differ diff --git a/test/widgets/goldens/yield_card_network_icon.png b/test/widgets/goldens/yield_card_network_icon.png new file mode 100644 index 0000000..cd09bcb Binary files /dev/null and b/test/widgets/goldens/yield_card_network_icon.png differ diff --git a/test/widgets/goldens/yield_card_selected.png b/test/widgets/goldens/yield_card_selected.png new file mode 100644 index 0000000..a648b35 Binary files /dev/null and b/test/widgets/goldens/yield_card_selected.png differ 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 5168c39..ede1768 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 95ddd36..e2f2555 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/token_selector_button_test.dart b/test/widgets/token_selector_button/token_selector_button_test.dart index c7505ec..fb380e1 100644 --- a/test/widgets/token_selector_button/token_selector_button_test.dart +++ b/test/widgets/token_selector_button/token_selector_button_test.dart @@ -6,7 +6,6 @@ import 'package:web3kit/web3kit.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/token_list_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'; @@ -30,17 +29,18 @@ void main() { appCubit = AppCubitMock(); wallet = WalletMock(); - registerFallbackValue(Networks.sepolia); + registerFallbackValue(AppNetworks.sepolia); inject.registerFactory(() => mockZupCachedImage()); inject.registerLazySingleton( () => TokenSelectorModalCubit(tokensRepository, appCubit, wallet), ); + inject.registerFactory(() => appCubit); inject.registerLazySingleton(() => Debouncer(milliseconds: 0)); - when(() => tokensRepository.getTokenList(any())).thenAnswer((_) async => TokenListDto.fixture()); + when(() => tokensRepository.getPopularTokens(any())).thenAnswer((_) async => [TokenDto.fixture()]); - when(() => appCubit.selectedNetwork).thenAnswer((_) => Networks.sepolia); + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.sepolia); }); tearDown(() => inject.reset()); 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 new file mode 100644 index 0000000..b99562e Binary files /dev/null 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_loading.png b/test/widgets/token_selector_modal/goldens/token_selector_modal_loading.png index 5e4ef75..2a4c07f 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_success.png b/test/widgets/token_selector_modal/goldens/token_selector_modal_success.png index df9ac8c..b9eb004 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/token_selector_modal_cubit_test.dart b/test/widgets/token_selector_modal/token_selector_modal_cubit_test.dart index 62d6cbb..3f2868a 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 @@ -4,7 +4,6 @@ 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/token_list_dto.dart'; import 'package:zup_app/core/enums/networks.dart'; import 'package:zup_app/core/repositories/tokens_repository.dart'; import 'package:zup_app/widgets/token_selector_modal/token_selector_modal_cubit.dart'; @@ -21,21 +20,21 @@ void main() { appCubit = AppCubitMock(); tokensRepository = TokensRepositoryMock(); wallet = WalletMock(); - registerFallbackValue(Networks.sepolia); + registerFallbackValue(AppNetworks.sepolia); sut = TokenSelectorModalCubit(tokensRepository, appCubit, wallet); - when(() => appCubit.selectedNetwork).thenAnswer((_) => Networks.sepolia); - when(() => tokensRepository.getTokenList(any())).thenAnswer((_) async => TokenListDto.fixture()); + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.sepolia); + when(() => tokensRepository.getPopularTokens(any())).thenAnswer((_) async => [TokenDto.fixture()]); when(() => tokensRepository.searchToken(any(), any())).thenAnswer((_) async => []); }); test( "Whe calling `fetchTokenList` and it has already been called in the same network, it should return the cached token list", () async { - final tokenList = TokenListDto.fixture().copyWith(mostUsedTokens: []); + final tokenList = [TokenDto.fixture()]; - when(() => tokensRepository.getTokenList(any())).thenAnswer((_) async => tokenList); + when(() => tokensRepository.getPopularTokens(any())).thenAnswer((_) async => tokenList); expectLater( sut.stream, @@ -56,49 +55,49 @@ void main() { await sut.fetchTokenList(); - verify(() => tokensRepository.getTokenList(any())).called(1); + verify(() => tokensRepository.getPopularTokens(any())).called(1); }); test( "When calling `fetchTokenList` and it has not already been called yet in the current network, it should get the tokens list again", () async { - final tokenList1 = TokenListDto.fixture(); - when(() => tokensRepository.getTokenList(any())).thenAnswer((_) async => tokenList1); - when(() => appCubit.selectedNetwork).thenAnswer((_) => Networks.sepolia); + final tokenList1 = [TokenDto.fixture()]; + when(() => tokensRepository.getPopularTokens(any())).thenAnswer((_) async => tokenList1); + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.sepolia); await sut.fetchTokenList(); - const tokenList2 = TokenListDto(); - when(() => tokensRepository.getTokenList(any())).thenAnswer((_) async => tokenList2); - when(() => appCubit.selectedNetwork).thenAnswer((_) => Networks.mainnet); + final tokenList2 = [TokenDto.fixture()]; + when(() => tokensRepository.getPopularTokens(any())).thenAnswer((_) async => tokenList2); + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.mainnet); await sut.fetchTokenList(); expect((await sut.tokenList).hashCode, tokenList2.hashCode); - verify(() => tokensRepository.getTokenList(any())).called(2); + verify(() => tokensRepository.getPopularTokens(any())).called(2); }); test( "When calling `fetchTokenList` switching networks, and the current network has already been called, it should return the cached list ", () async { - final tokenList1 = TokenListDto.fixture(); - when(() => tokensRepository.getTokenList(any())).thenAnswer((_) async => tokenList1); - when(() => appCubit.selectedNetwork).thenAnswer((_) => Networks.sepolia); + final tokenList1 = [TokenDto.fixture()]; + when(() => tokensRepository.getPopularTokens(any())).thenAnswer((_) async => tokenList1); + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.sepolia); await sut.fetchTokenList(); - const tokenList2 = TokenListDto(); - when(() => tokensRepository.getTokenList(any())).thenAnswer((_) async => tokenList2); - when(() => appCubit.selectedNetwork).thenAnswer((_) => Networks.mainnet); + final tokenList2 = [TokenDto.fixture()]; + when(() => tokensRepository.getPopularTokens(any())).thenAnswer((_) async => tokenList2); + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.mainnet); await sut.fetchTokenList(); - when(() => appCubit.selectedNetwork).thenAnswer((_) => Networks.sepolia); - when(() => tokensRepository.getTokenList(any())).thenAnswer((_) async => tokenList1); + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.sepolia); + when(() => tokensRepository.getPopularTokens(any())).thenAnswer((_) async => tokenList1); await sut.fetchTokenList(); expect((await sut.tokenList).hashCode, tokenList1.hashCode); - verify(() => tokensRepository.getTokenList(any())).called(2); + verify(() => tokensRepository.getPopularTokens(any())).called(2); }); test("""When calling `fetchTokenList` and right after calling @@ -107,9 +106,9 @@ void main() { not emit the state of loaded, but should update the cached list""", () async { const requestDuration = Duration(milliseconds: 1); - final tokenList = TokenListDto.fixture(); + final tokenList = [TokenDto.fixture()]; - when(() => tokensRepository.getTokenList(any())).thenAnswer( + when(() => tokensRepository.getPopularTokens(any())).thenAnswer( (_) async => Future.delayed(requestDuration, () => tokenList), ); @@ -131,7 +130,7 @@ void main() { error, it should not update the cached list or emit error state""", () async { const requestDuration = Duration(milliseconds: 1); - when(() => tokensRepository.getTokenList(any())) + when(() => tokensRepository.getPopularTokens(any())) .thenAnswer((_) => Future.delayed(requestDuration, () => throw "dale")); sut.fetchTokenList(); @@ -143,7 +142,7 @@ void main() { }); test("when calling load data, and the repository throws an error, it should emit an error state", () async { - when(() => tokensRepository.getTokenList(any())).thenThrow("dale"); + when(() => tokensRepository.getPopularTokens(any())).thenThrow("dale"); await sut.fetchTokenList(); @@ -151,9 +150,9 @@ void main() { }); test("when calling load data, and the repository returns success, it should emit the success state", () async { - final tokenList = TokenListDto.fixture(); + final tokenList = [TokenDto.fixture()]; - when(() => tokensRepository.getTokenList(any())).thenAnswer((_) async => tokenList); + when(() => tokensRepository.getPopularTokens(any())).thenAnswer((_) async => tokenList); await sut.fetchTokenList(); @@ -256,29 +255,54 @@ void main() { await sut.close(); }); - test("""When calling `fetchTokenList` without a connected wallet, then connecting a wallet, - and calling `fetchTokenList` again, it should refetch the token list passing the user address - to the repository""", () async { - final signer = SignerMock(); - when(() => wallet.signer).thenReturn(null); - await sut.fetchTokenList(); - - when(() => wallet.signer).thenReturn(signer); - when(() => signer.address).thenAnswer((_) async => "0x99E3CfADCD8Feecb5DdF91f88998cFfB3145F78c"); - await sut.fetchTokenList(); - - verify( - () => tokensRepository.getTokenList(any(), userAddress: "0x99E3CfADCD8Feecb5DdF91f88998cFfB3145F78c"), - ).called(1); - verify(() => tokensRepository.getTokenList(any())).called(1); - }); - test("When calling `fetchTokenList` with 'forceRefresh' true, it should refetch the token list ignoring the cache", () async { await sut.fetchTokenList(forceRefresh: true); await sut.fetchTokenList(forceRefresh: true); await sut.fetchTokenList(forceRefresh: true); - verify(() => tokensRepository.getTokenList(any())).called(3); + verify(() => tokensRepository.getPopularTokens(any())).called(3); + }); + + test( + "When callling 'searchToken' with a valid ethereum address, and the network is all networks, it should emit the search not found state", + () async { + when(() => appCubit.selectedNetwork).thenReturn(AppNetworks.allNetworks); + + const address = "0x0000000000000000000000000000000000000000"; + await sut.searchToken(address); + + expect(sut.state, const TokenSelectorModalState.searchNotFound(address)); + verifyNever(() => tokensRepository.searchToken(any(), any())); + }); + + test("""When calling 'searchToken' and all the tokens in the list returned does not have name and symbol, + it should emit the search not found state""", () async { + final returnedList = [ + const TokenDto(name: "", symbol: "", decimals: 0, logoUrl: "", addresses: {}), + const TokenDto(name: "", symbol: "", decimals: 0, logoUrl: "", addresses: {}), + ]; + + when(() => tokensRepository.searchToken(any(), any())).thenAnswer((_) async => returnedList); + + await sut.searchToken("dale"); + + expect(sut.state, const TokenSelectorModalState.searchNotFound("dale")); + }); + + test("""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 returnedList = [ + const TokenDto(name: "", symbol: "", decimals: 0, logoUrl: "", addresses: {}), + const TokenDto(name: "", symbol: "", decimals: 0, logoUrl: "", addresses: {}), + namedToken, + ]; + + when(() => tokensRepository.searchToken(any(), any())).thenAnswer((_) async => returnedList); + + await sut.searchToken("dale"); + + expect(sut.state, TokenSelectorModalState.searchSuccess([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 d5bf6dd..04c5a5b 100644 --- a/test/widgets/token_selector_modal/token_selector_modal_test.dart +++ b/test/widgets/token_selector_modal/token_selector_modal_test.dart @@ -5,7 +5,6 @@ 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/token_list_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'; @@ -24,15 +23,16 @@ void main() { setUp(() { appCubit = AppCubitMock(); tokensRepository = TokensRepositoryMock(); - registerFallbackValue(Networks.sepolia); + registerFallbackValue(AppNetworks.sepolia); cubit = TokenSelectorModalCubitMock(); inject.registerFactory(() => cubit); inject.registerFactory(() => mockZupCachedImage()); inject.registerFactory(() => Debouncer(milliseconds: 0)); + inject.registerFactory(() => appCubit); - when(() => appCubit.selectedNetwork).thenAnswer((_) => Networks.sepolia); - when(() => tokensRepository.getTokenList(any())).thenAnswer((_) async => TokenListDto.fixture()); + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.sepolia); + when(() => tokensRepository.getPopularTokens(any())).thenAnswer((_) async => [TokenDto.fixture()]); when(() => cubit.stream).thenAnswer((_) => const Stream.empty()); when(() => cubit.state).thenReturn(const TokenSelectorModalState.initial()); when(() => cubit.fetchTokenList()).thenAnswer((_) async {}); @@ -192,7 +192,7 @@ void main() { zGoldenTest("When the state is success, it should show the success state", goldenFileName: "token_selector_modal_success", (tester) async { - final tokenList = TokenListDto.fixture(); + final tokenList = [TokenDto.fixture()]; when(() => cubit.state).thenReturn(TokenSelectorModalState.success(tokenList)); @@ -200,69 +200,12 @@ void main() { await tester.pumpAndSettle(); }); - zGoldenTest("When clicking the mini button, it should callback with selected token", (tester) async { - const tokenList = TokenListDto( - mostUsedTokens: [TokenDto(address: "addr"), TokenDto()], - popularTokens: [TokenDto()], - userTokens: [TokenDto()], - ); - TokenDto? selectedToken; - - when(() => cubit.state).thenReturn(const TokenSelectorModalState.success(tokenList)); - - await tester.pumpDeviceBuilder( - await goldenBuilder( - onSelectToken: (token) { - return selectedToken = token; - }, - ), - wrapper: GoldenConfig.localizationsWrapper()); - - await tester.pumpAndSettle(); - - await tester.tap(find.byKey(const Key("most-used-token-0"))); - await tester.pumpAndSettle(); - - expect(selectedToken.hashCode, tokenList.mostUsedTokens.first.hashCode); - }); - - zGoldenTest("When clicking the token card in the `My Tokens` section, it should callback with selected token", - (tester) async { - const tokenList = TokenListDto( - mostUsedTokens: [TokenDto(address: "addr"), TokenDto()], - popularTokens: [TokenDto()], - userTokens: [TokenDto()], - ); - TokenDto? selectedToken; - - when(() => cubit.state).thenReturn(const TokenSelectorModalState.success(tokenList)); - - await tester.pumpDeviceBuilder( - await goldenBuilder( - onSelectToken: (token) { - return selectedToken = token; - }, - ), - wrapper: GoldenConfig.localizationsWrapper()); - - await tester.pumpAndSettle(); - - await tester.tap(find.byKey(const Key("user-token-0"))); - await tester.pumpAndSettle(); - - expect(selectedToken.hashCode, tokenList.userTokens.first.hashCode); - }); - zGoldenTest("When clicking the token card in the `Popular Tokens` section, it should callback with selected token", (tester) async { - const tokenList = TokenListDto( - mostUsedTokens: [TokenDto(address: "addr"), TokenDto()], - popularTokens: [TokenDto()], - userTokens: [TokenDto()], - ); + final tokenList = [TokenDto.fixture()]; TokenDto? selectedToken; - when(() => cubit.state).thenReturn(const TokenSelectorModalState.success(tokenList)); + when(() => cubit.state).thenReturn(TokenSelectorModalState.success(tokenList)); await tester.pumpDeviceBuilder( await goldenBuilder( @@ -277,28 +220,16 @@ void main() { await tester.tap(find.byKey(const Key("popular-token-0"))); await tester.pumpAndSettle(); - expect(selectedToken.hashCode, tokenList.popularTokens.first.hashCode); + expect(selectedToken.hashCode, tokenList.first.hashCode); }); zGoldenTest( - "When clicking the refresh button in the my tokens section, it should refetch the token list ignoring the cache", - (tester) async { - final tokenList = TokenListDto( - mostUsedTokens: [TokenDto.fixture()], - popularTokens: [const TokenDto()], - userTokens: [TokenDto.fixture()], - ); - - when(() => cubit.state).thenReturn(TokenSelectorModalState.success(tokenList)); - when(() => cubit.fetchTokenList(forceRefresh: any(named: "forceRefresh"))).thenAnswer((_) async {}); + "When the network is all networks, it should show an alert about only being able to search by name or symbol", + goldenFileName: "token_selector_modal_all_networks", (tester) async { + when(() => appCubit.selectedNetwork).thenReturn(AppNetworks.allNetworks); + when(() => cubit.state).thenReturn(TokenSelectorModalState.success([TokenDto.fixture()])); - await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); - await tester.pumpAndSettle(); - - await tester.tap(find.byKey(const Key("refresh-button"))); - await tester.pumpAndSettle(); - - verify(() => cubit.fetchTokenList(forceRefresh: true)).called(1); - }, - ); + await tester.pumpDeviceBuilder(await goldenBuilder(), wrapper: GoldenConfig.localizationsWrapper()); + await tester.pumpAndSettle(); + }); } diff --git a/test/widgets/yield_card_test.dart b/test/widgets/yield_card_test.dart new file mode 100644 index 0000000..0028c7d --- /dev/null +++ b/test/widgets/yield_card_test.dart @@ -0,0 +1,100 @@ +import 'package:flutter/src/widgets/basic.dart'; +import 'package:flutter_test/flutter_test.dart'; +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/dtos/yield_dto.dart'; +import 'package:zup_app/core/enums/networks.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 '../golden_config.dart'; +import '../mocks.dart'; + +void main() { + ZupCachedImage zupCachedImage = mockZupCachedImage(); + late AppCubit appCubit; + + setUp(() { + appCubit = AppCubitMock(); + + inject.registerFactory(() => appCubit); + inject.registerFactory(() => zupCachedImage); + + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.sepolia); + when(() => appCubit.selectedNetworkStream).thenAnswer((_) => const Stream.empty()); + }); + + tearDown(() => inject.reset()); + + Future goldenBuilder({ + YieldDto? currentYield, + Function(YieldDto? yield)? onChangeSelection, + bool isSelected = false, + YieldTimeFrame? timeFrame, + }) async => + await goldenDeviceBuilder(Center( + child: SizedBox( + width: 300, + child: Center( + child: YieldCard( + isSelected: isSelected, + onChangeSelection: (selectedYield) => onChangeSelection?.call(selectedYield), + timeFrame: timeFrame ?? YieldTimeFrame.day, + currentYield: currentYield ?? YieldDto.fixture(), + ), + ), + ), + )); + + zGoldenTest("When the app network is all networks, the yield card should display an icon of the network of the yield", + goldenFileName: "yield_card_network_icon", (tester) async { + when(() => appCubit.selectedNetwork).thenAnswer((_) => AppNetworks.allNetworks); + + await tester.pumpDeviceBuilder(await goldenBuilder()); + + await tester.pumpAndSettle(); + }); + + zGoldenTest("When passing `isSelected` as true, the yield card should be selected", + goldenFileName: "yield_card_selected", (tester) async { + await tester.pumpDeviceBuilder(await goldenBuilder(isSelected: true)); + + await tester.pumpAndSettle(); + }); + + zGoldenTest( + "When passing the 30d timeframe, the yield card should display the 30d yield", + goldenFileName: "yield_card_30d", + (tester) async { + final currentYield = YieldDto.fixture().copyWith(yield30d: 87654.98765); + await tester.pumpDeviceBuilder(await goldenBuilder(timeFrame: YieldTimeFrame.month, currentYield: currentYield)); + + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When passing the 24h timeframe, the yield card should display the 30d yield", + goldenFileName: "yield_card_24h", + (tester) async { + final currentYield = YieldDto.fixture().copyWith(yield24h: 1447.23); + await tester.pumpDeviceBuilder(await goldenBuilder(timeFrame: YieldTimeFrame.day, currentYield: currentYield)); + + await tester.pumpAndSettle(); + }, + ); + + zGoldenTest( + "When passing the 90d timeframe, the yield card should display the 90d yield", + goldenFileName: "yield_card_90d", + (tester) async { + final currentYield = YieldDto.fixture().copyWith(yield90d: 1535421.32); + await tester + .pumpDeviceBuilder(await goldenBuilder(timeFrame: YieldTimeFrame.threeMonth, currentYield: currentYield)); + + await tester.pumpAndSettle(); + }, + ); +} diff --git a/web/index.html b/web/index.html index f88831a..a5b9ac6 100644 --- a/web/index.html +++ b/web/index.html @@ -61,6 +61,6 @@ inject(); - +