diff --git a/assets/logos/bnb_chain.svg b/assets/logos/bnb_chain.svg
new file mode 100644
index 0000000..7f8d0da
--- /dev/null
+++ b/assets/logos/bnb_chain.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/abis/pancake_swap_infinity_cl_pool_manager.abi.json b/lib/abis/pancake_swap_infinity_cl_pool_manager.abi.json
new file mode 100644
index 0000000..1117a3b
--- /dev/null
+++ b/lib/abis/pancake_swap_infinity_cl_pool_manager.abi.json
@@ -0,0 +1,36 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "PoolId",
+ "name": "id",
+ "type": "bytes32"
+ }
+ ],
+ "name": "getSlot0",
+ "outputs": [
+ {
+ "internalType": "uint160",
+ "name": "sqrtPriceX96",
+ "type": "uint160"
+ },
+ {
+ "internalType": "int24",
+ "name": "tick",
+ "type": "int24"
+ },
+ {
+ "internalType": "uint24",
+ "name": "protocolFee",
+ "type": "uint24"
+ },
+ {
+ "internalType": "uint24",
+ "name": "lpFee",
+ "type": "uint24"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ }
+]
\ No newline at end of file
diff --git a/lib/app/create/deposit/deposit_page.dart b/lib/app/create/deposit/deposit_page.dart
index 50dcf05..9227e25 100644
--- a/lib/app/create/deposit/deposit_page.dart
+++ b/lib/app/create/deposit/deposit_page.dart
@@ -123,8 +123,8 @@ class _DepositPageState extends State
final price = tickToPrice(
tick: _cubit.latestPoolTick!,
- poolToken0Decimals: _cubit.selectedYield!.token0.decimals,
- poolToken1Decimals: _cubit.selectedYield!.token1.decimals,
+ poolToken0Decimals: _cubit.selectedYield!.token0NetworkDecimals,
+ poolToken1Decimals: _cubit.selectedYield!.token1NetworkDecimals,
);
return areTokensReversed ? price.priceAsQuoteToken : price.priceAsBaseToken;
@@ -215,14 +215,14 @@ class _DepositPageState extends State
final maxTickPrice = tickToPrice(
tick: V3V4PoolConstants.maxTick,
- poolToken0Decimals: _cubit.selectedYield!.token0.decimals,
- poolToken1Decimals: _cubit.selectedYield!.token1.decimals,
+ poolToken0Decimals: _cubit.selectedYield!.token0NetworkDecimals,
+ poolToken1Decimals: _cubit.selectedYield!.token1NetworkDecimals,
);
final minTickPrice = tickToPrice(
tick: V3V4PoolConstants.minTick,
- poolToken0Decimals: _cubit.selectedYield!.token0.decimals,
- poolToken1Decimals: _cubit.selectedYield!.token1.decimals,
+ poolToken0Decimals: _cubit.selectedYield!.token0NetworkDecimals,
+ poolToken1Decimals: _cubit.selectedYield!.token1NetworkDecimals,
);
double getMinPrice() {
@@ -756,8 +756,8 @@ class _DepositPageState extends State
"1 ${baseToken.symbol} ≈ ${() {
final currentPrice = tickToPrice(
tick: poolTickSnapshot.data ?? BigInt.zero,
- poolToken0Decimals: _cubit.selectedYield!.token0.decimals,
- poolToken1Decimals: _cubit.selectedYield!.token1.decimals,
+ poolToken0Decimals: _cubit.selectedYield!.token0NetworkDecimals,
+ poolToken1Decimals: _cubit.selectedYield!.token1NetworkDecimals,
);
return areTokensReversed ? currentPrice.priceAsQuoteToken : currentPrice.priceAsBaseToken;
@@ -826,8 +826,8 @@ class _DepositPageState extends State
});
},
initialPrice: minPrice,
- poolToken0: _cubit.selectedYield!.token0,
- poolToken1: _cubit.selectedYield!.token1,
+ poolToken0Decimals: _cubit.selectedYield!.token0NetworkDecimals,
+ poolToken1Decimals: _cubit.selectedYield!.token1NetworkDecimals,
isReversed: areTokensReversed,
displayBaseTokenSymbol: baseToken.symbol,
displayQuoteTokenSymbol: quoteToken.symbol,
@@ -873,8 +873,8 @@ class _DepositPageState extends State
type: RangeSelectorType.maxPrice,
isInfinity: isMaxRangeInfinity,
initialPrice: maxPrice,
- poolToken0: _cubit.selectedYield!.token0,
- poolToken1: _cubit.selectedYield!.token1,
+ poolToken0Decimals: _cubit.selectedYield!.token0NetworkDecimals,
+ poolToken1Decimals: _cubit.selectedYield!.token1NetworkDecimals,
isReversed: areTokensReversed,
tickSpacing: _cubit.selectedYield!.tickSpacing,
rangeController: maxRangeController,
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 855b04c..a0eb653 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
@@ -120,17 +120,17 @@ class _PreviewDepositModalState extends State with V3PoolCo
double get quoteTokenAmount => isReversedLocal ? widget.token0DepositAmount : widget.token1DepositAmount;
PreviewDepositModalCubit get cubit => context.read();
BigInt get token0DepositAmount =>
- widget.token0DepositAmount.parseTokenAmount(decimals: widget.currentYield.token0.decimals);
+ widget.token0DepositAmount.parseTokenAmount(decimals: widget.currentYield.token0NetworkDecimals);
BigInt get token1DepositAmount =>
- widget.token1DepositAmount.parseTokenAmount(decimals: widget.currentYield.token1.decimals);
+ widget.token1DepositAmount.parseTokenAmount(decimals: widget.currentYield.token1NetworkDecimals);
double get currentPrice {
final currentTick = cubit.latestPoolTick;
final price = tickToPrice(
tick: currentTick,
- poolToken0Decimals: widget.currentYield.token0.decimals,
- poolToken1Decimals: widget.currentYield.token1.decimals,
+ poolToken0Decimals: widget.currentYield.token0NetworkDecimals,
+ poolToken1Decimals: widget.currentYield.token1NetworkDecimals,
);
return isReversedLocal ? price.priceAsQuoteToken : price.priceAsBaseToken;
@@ -142,16 +142,16 @@ class _PreviewDepositModalState extends State with V3PoolCo
return priceToTick(
price: (widget.isReversed == !isReversedLocal) ? widget.maxPrice.price : widget.minPrice.price,
- poolToken0Decimals: widget.currentYield.token0.decimals,
- poolToken1Decimals: widget.currentYield.token1.decimals,
+ poolToken0Decimals: widget.currentYield.token0NetworkDecimals,
+ poolToken1Decimals: widget.currentYield.token1NetworkDecimals,
isReversed: widget.isReversed,
);
}
({double priceAsBaseToken, double priceAsQuoteToken}) price() => tickToPrice(
tick: tick(),
- poolToken0Decimals: widget.currentYield.token0.decimals,
- poolToken1Decimals: widget.currentYield.token1.decimals,
+ poolToken0Decimals: widget.currentYield.token0NetworkDecimals,
+ poolToken1Decimals: widget.currentYield.token1NetworkDecimals,
);
return isReversedLocal ? price().priceAsQuoteToken : price().priceAsBaseToken;
@@ -163,16 +163,16 @@ class _PreviewDepositModalState extends State with V3PoolCo
return priceToTick(
price: (widget.isReversed == !isReversedLocal) ? widget.minPrice.price : widget.maxPrice.price,
- poolToken0Decimals: widget.currentYield.token0.decimals,
- poolToken1Decimals: widget.currentYield.token1.decimals,
+ poolToken0Decimals: widget.currentYield.token0NetworkDecimals,
+ poolToken1Decimals: widget.currentYield.token1NetworkDecimals,
isReversed: widget.isReversed,
);
}
({double priceAsBaseToken, double priceAsQuoteToken}) price() => tickToPrice(
tick: tick(),
- poolToken0Decimals: widget.currentYield.token0.decimals,
- poolToken1Decimals: widget.currentYield.token1.decimals,
+ poolToken0Decimals: widget.currentYield.token0NetworkDecimals,
+ poolToken1Decimals: widget.currentYield.token1NetworkDecimals,
);
return isReversedLocal ? price().priceAsQuoteToken : price().priceAsBaseToken;
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 e537ec9..9de2af3 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
@@ -175,8 +175,8 @@ class PreviewDepositModalCubit extends Cubit with V3Po
return priceToTick(
price: isReversed ? maxPrice : minPrice,
- poolToken0Decimals: _yield.token0.decimals,
- poolToken1Decimals: _yield.token1.decimals,
+ poolToken0Decimals: _yield.token0NetworkDecimals,
+ poolToken1Decimals: _yield.token1NetworkDecimals,
isReversed: isReversed,
);
}
@@ -194,8 +194,8 @@ class PreviewDepositModalCubit extends Cubit with V3Po
return priceToTick(
price: isReversed ? minPrice : maxPrice,
- poolToken0Decimals: _yield.token0.decimals,
- poolToken1Decimals: _yield.token1.decimals,
+ poolToken0Decimals: _yield.token0NetworkDecimals,
+ poolToken1Decimals: _yield.token1NetworkDecimals,
isReversed: isReversed,
);
}
@@ -253,8 +253,8 @@ class PreviewDepositModalCubit extends Cubit with V3Po
emit(PreviewDepositModalState.depositSuccess(txId: tx.hash));
_zupAnalytics.logDeposit(
depositedYield: _yield,
- amount0Formatted: amount0Desired.parseTokenAmount(decimals: _yield.token0.decimals),
- amount1Formatted: amount1Desired.parseTokenAmount(decimals: _yield.token1.decimals),
+ amount0Formatted: amount0Desired.parseTokenAmount(decimals: _yield.token0NetworkDecimals),
+ amount1Formatted: amount1Desired.parseTokenAmount(decimals: _yield.token1NetworkDecimals),
walletAddress: recipient,
);
} catch (e) {
diff --git a/lib/app/create/deposit/widgets/range_selector.dart b/lib/app/create/deposit/widgets/range_selector.dart
index 9f25473..a797454 100644
--- a/lib/app/create/deposit/widgets/range_selector.dart
+++ b/lib/app/create/deposit/widgets/range_selector.dart
@@ -1,6 +1,5 @@
import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart';
-import 'package:zup_app/core/dtos/token_dto.dart';
import 'package:zup_app/core/extensions/num_extension.dart';
import 'package:zup_app/core/mixins/v3_pool_conversors_mixin.dart';
import 'package:zup_app/core/token_amount_input_formatter.dart';
@@ -55,8 +54,8 @@ class RangeController extends ChangeNotifier {
class RangeSelector extends StatefulWidget {
const RangeSelector({
super.key,
- required this.poolToken0,
- required this.poolToken1,
+ required this.poolToken0Decimals,
+ required this.poolToken1Decimals,
required this.displayBaseTokenSymbol,
required this.displayQuoteTokenSymbol,
required this.isReversed,
@@ -70,8 +69,8 @@ class RangeSelector extends StatefulWidget {
this.state = const RangeSelectorState(type: RangeSelectorStateType.regular),
});
- final TokenDto poolToken0;
- final TokenDto poolToken1;
+ final int poolToken0Decimals;
+ final int poolToken1Decimals;
final String displayBaseTokenSymbol;
final String displayQuoteTokenSymbol;
final bool isReversed;
@@ -116,8 +115,8 @@ class _RangeSelectorState extends State with V3PoolConversorsMixi
double getAdjustedPrice(double price) {
final adjustedPrice = priceToClosestValidPrice(
price: price,
- poolToken0Decimals: widget.poolToken0.decimals,
- poolToken1Decimals: widget.poolToken1.decimals,
+ poolToken0Decimals: widget.poolToken0Decimals,
+ poolToken1Decimals: widget.poolToken1Decimals,
tickSpacing: widget.tickSpacing,
isReversed: widget.isReversed,
);
@@ -131,13 +130,16 @@ class _RangeSelectorState extends State with V3PoolConversorsMixi
if (currentPrice == 0 && !increasing) return;
if ((currentPrice == 0 || widget.isInfinity) && increasing) {
- final minimumPrice = tickToPrice(
- tick: BigInt.from(widget.tickSpacing),
- poolToken0Decimals: widget.poolToken0.decimals,
- poolToken1Decimals: widget.poolToken1.decimals,
+ final minimumPrice = priceToClosestValidPrice(
+ price: 0.000000000000000001,
+ poolToken0Decimals: widget.poolToken0Decimals,
+ poolToken1Decimals: widget.poolToken1Decimals,
+ tickSpacing: widget.tickSpacing,
+ isReversed: widget.isReversed,
);
- userTypedValue = minimumPrice.priceAsBaseToken.toString();
+ userTypedValue = minimumPrice.price.toString();
+
return adjustTypedAmountAndCallback();
}
@@ -145,8 +147,8 @@ class _RangeSelectorState extends State with V3PoolConversorsMixi
final BigInt currentTick = tickToClosestValidTick(
tick: priceToTick(
price: currentPrice,
- poolToken0Decimals: widget.poolToken0.decimals,
- poolToken1Decimals: widget.poolToken1.decimals,
+ poolToken0Decimals: widget.poolToken0Decimals,
+ poolToken1Decimals: widget.poolToken1Decimals,
isReversed: widget.isReversed,
),
tickSpacing: widget.tickSpacing,
@@ -163,8 +165,8 @@ class _RangeSelectorState extends State with V3PoolConversorsMixi
double nextPrice() {
final nextPrice = tickToPrice(
tick: nextTick(),
- poolToken0Decimals: widget.poolToken0.decimals,
- poolToken1Decimals: widget.poolToken1.decimals,
+ poolToken0Decimals: widget.poolToken0Decimals,
+ poolToken1Decimals: widget.poolToken1Decimals,
);
if (widget.isReversed) return nextPrice.priceAsQuoteToken;
@@ -179,8 +181,8 @@ class _RangeSelectorState extends State with V3PoolConversorsMixi
if (widget.initialPrice != null) {
final adjustedInitialPrice = priceToClosestValidPrice(
price: widget.initialPrice ?? 0,
- poolToken0Decimals: widget.poolToken0.decimals,
- poolToken1Decimals: widget.poolToken1.decimals,
+ poolToken0Decimals: widget.poolToken0Decimals,
+ poolToken1Decimals: widget.poolToken1Decimals,
tickSpacing: widget.tickSpacing,
isReversed: widget.isReversed,
);
diff --git a/lib/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button.dart b/lib/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button.dart
index 88ca06a..0092138 100644
--- a/lib/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button.dart
+++ b/lib/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button.dart
@@ -27,7 +27,7 @@ class _ExchangesFilterDropdownButtonState extends State cubit!.protocols
.where(
- (protocol) => !cache.blockedProtocolsIds.contains(protocol.id),
+ (protocol) => !cache.blockedProtocolsIds.contains(protocol.rawId),
)
.length;
@@ -122,10 +122,10 @@ class _ExchangesFilterDropdownButtonState extends State ZupCheckboxItem(
- id: protocol.id,
+ id: protocol.rawId,
title: protocol.name,
icon: zupCachedImage.build(protocol.logo, radius: 50),
- isChecked: !cache.blockedProtocolsIds.contains(protocol.id),
+ isChecked: !cache.blockedProtocolsIds.contains(protocol.rawId),
isDisabled: false,
),
)
diff --git a/lib/core/dtos/protocol_dto.dart b/lib/core/dtos/protocol_dto.dart
index 1825eeb..3c23722 100644
--- a/lib/core/dtos/protocol_dto.dart
+++ b/lib/core/dtos/protocol_dto.dart
@@ -1,15 +1,19 @@
import 'package:freezed_annotation/freezed_annotation.dart';
+import 'package:zup_app/core/enums/protocol_id.dart';
part 'protocol_dto.freezed.dart';
part 'protocol_dto.g.dart';
+String _readRawProtocolId(Map map, String key) => map['id'];
+
@freezed
class ProtocolDto with _$ProtocolDto {
const ProtocolDto._();
@JsonSerializable(explicitToJson: true)
const factory ProtocolDto({
- @Default("") String id,
+ @Default("") @JsonKey(readValue: _readRawProtocolId) String rawId,
+ @Default(ProtocolId.unknown) @JsonKey(unknownEnumValue: ProtocolId.unknown) ProtocolId id,
@Default("") String name,
@Default("") String url,
@Default("") String logo,
@@ -18,6 +22,8 @@ class ProtocolDto with _$ProtocolDto {
factory ProtocolDto.fromJson(Map json) => _$ProtocolDtoFromJson(json);
factory ProtocolDto.fixture() => const ProtocolDto(
+ rawId: "1",
+ id: ProtocolId.unknown,
name: "Uniswap",
url: "https://app.uniswap.org/pool",
logo: "https://raw.githubusercontent.com/trustwallet/assets/master/dapps/app.uniswap.org.png",
diff --git a/lib/core/dtos/token_dto.dart b/lib/core/dtos/token_dto.dart
index e69ddef..2c20e2a 100644
--- a/lib/core/dtos/token_dto.dart
+++ b/lib/core/dtos/token_dto.dart
@@ -13,7 +13,7 @@ class TokenDto with _$TokenDto {
@Default("") String name,
@Default("") String logoUrl,
@Default({}) Map addresses,
- @Default(0) int decimals,
+ @Default({}) Map decimals,
}) = _TokenDto;
factory TokenDto.fromJson(Map json) => _$TokenDtoFromJson(json);
@@ -23,6 +23,13 @@ class TokenDto with _$TokenDto {
factory TokenDto.fixture() => TokenDto(
symbol: 'WETH',
name: 'Wrapped Ether',
+ decimals: Map.fromEntries(
+ AppNetworks.values.where((network) => !network.isAllNetworks).map(
+ (network) {
+ return MapEntry(network.chainId, 18);
+ },
+ ),
+ ),
addresses: Map.fromEntries(
AppNetworks.values.where((network) => !network.isAllNetworks).map(
(network) {
diff --git a/lib/core/dtos/yield_dto.dart b/lib/core/dtos/yield_dto.dart
index 191d414..df29c23 100644
--- a/lib/core/dtos/yield_dto.dart
+++ b/lib/core/dtos/yield_dto.dart
@@ -62,6 +62,9 @@ class YieldDto with _$YieldDto {
bool get isToken0Native => token0.addresses[network.chainId] == EthereumConstants.zeroAddress;
bool get isToken1Native => token1.addresses[network.chainId] == EthereumConstants.zeroAddress;
+ int get token0NetworkDecimals => token0.decimals[network.chainId]!;
+ int get token1NetworkDecimals => token1.decimals[network.chainId]!;
+
factory YieldDto.fromJson(Map json) => _$YieldDtoFromJson(json);
factory YieldDto.fixture() => YieldDto(
@@ -75,7 +78,9 @@ class YieldDto with _$YieldDto {
poolType: PoolType.v3,
token0: TokenDto.fixture().copyWith(
symbol: "USDC",
- decimals: 6,
+ decimals: {
+ AppNetworks.sepolia.chainId: 6,
+ },
addresses: {
AppNetworks.sepolia.chainId: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
},
@@ -84,7 +89,9 @@ class YieldDto with _$YieldDto {
),
token1: TokenDto.fixture().copyWith(
symbol: "WETH",
- decimals: 18,
+ decimals: {
+ AppNetworks.sepolia.chainId: 18,
+ },
addresses: {
AppNetworks.sepolia.chainId: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
},
diff --git a/lib/core/dtos/yields_dto.dart b/lib/core/dtos/yields_dto.dart
index e39cae7..ac83d41 100644
--- a/lib/core/dtos/yields_dto.dart
+++ b/lib/core/dtos/yields_dto.dart
@@ -4,6 +4,7 @@ import 'package:zup_app/core/dtos/protocol_dto.dart';
import 'package:zup_app/core/dtos/token_dto.dart';
import 'package:zup_app/core/dtos/yield_dto.dart';
import 'package:zup_app/core/enums/pool_type.dart';
+import 'package:zup_app/core/enums/protocol_id.dart';
part 'yields_dto.freezed.dart';
part 'yields_dto.g.dart';
@@ -33,21 +34,21 @@ class YieldsDto with _$YieldsDto {
factory YieldsDto.fixture() => YieldsDto(
filters: PoolSearchFiltersDto.fixture(),
pools: [
- const YieldDto(
+ YieldDto(
latestTick: "637812562",
positionManagerAddress: "0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4",
poolType: PoolType.v3,
- token0: TokenDto(
+ token0: const TokenDto(
addresses: {11155111: "0x02a3e7E0480B668bD46b42852C58363F93e3bA5C"},
- decimals: 6,
+ decimals: {11155111: 6},
logoUrl:
"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/scroll/assets/0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4/logo.png",
name: "USDC",
symbol: "USDC",
),
- token1: TokenDto(
+ token1: const TokenDto(
addresses: {11155111: "0x5300000000000000000000000000000000000004"},
- decimals: 18,
+ decimals: {11155111: 18},
logoUrl:
"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/scroll/assets/0x5300000000000000000000000000000000000004/logo.png",
name: "Wrapped Ether",
@@ -62,6 +63,8 @@ class YieldsDto with _$YieldsDto {
totalValueLockedUSD: 65434567890.21,
feeTier: 500,
protocol: ProtocolDto(
+ id: ProtocolId.pancakeSwapInfinityCL,
+ rawId: ProtocolId.pancakeSwapInfinityCL.toRawJsonValue,
name: "PancakeSwap",
logo:
"https://raw.githubusercontent.com/trustwallet/assets/master/dapps/exchange.pancakeswap.finance.png",
diff --git a/lib/core/enums/networks.dart b/lib/core/enums/networks.dart
index a29915a..c891f44 100644
--- a/lib/core/enums/networks.dart
+++ b/lib/core/enums/networks.dart
@@ -2,13 +2,13 @@ import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:web3kit/web3kit.dart';
-import 'package:zup_app/core/dtos/token_dto.dart';
import 'package:zup_app/gen/assets.gen.dart';
enum AppNetworks {
allNetworks,
mainnet,
// base,
+ bnb,
unichain,
scroll,
sepolia;
@@ -47,6 +47,7 @@ enum AppNetworks {
allNetworks => false,
// base => false,
unichain => false,
+ bnb => false
};
String get label => switch (this) {
@@ -56,6 +57,7 @@ enum AppNetworks {
allNetworks => "All Networks",
// base => "Base",
unichain => "Unichain",
+ bnb => "BNB Chain",
};
Widget get icon => switch (this) {
@@ -65,6 +67,7 @@ enum AppNetworks {
// base => Assets.logos.base.svg(),
unichain => Assets.logos.unichain.svg(),
allNetworks => Assets.icons.all.svg(),
+ bnb => Assets.logos.bnbChain.svg()
};
ChainInfo get chainInfo => switch (this) {
@@ -100,10 +103,17 @@ enum AppNetworks {
unichain => ChainInfo(
hexChainId: "0x82",
chainName: label,
- blockExplorerUrls: const ["https://uniscan.xyz/"],
+ blockExplorerUrls: const ["https://uniscan.xyz"],
nativeCurrency: NativeCurrencies.eth.currencyInfo,
rpcUrls: [rpcUrl],
),
+ bnb => ChainInfo(
+ hexChainId: "0x38",
+ chainName: label,
+ blockExplorerUrls: const ["https://bscscan.com"],
+ nativeCurrency: NativeCurrencies.bnb.currencyInfo,
+ rpcUrls: [rpcUrl],
+ ),
};
String get wrappedNativeTokenAddress => switch (this) {
@@ -112,48 +122,8 @@ enum AppNetworks {
mainnet => "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
scroll => "0x5300000000000000000000000000000000000004",
// base => "0x4200000000000000000000000000000000000006",
- unichain => "0x4200000000000000000000000000000000000006"
- };
-
- TokenDto get wrappedNative => switch (this) {
- allNetworks => throw UnimplementedError("allNetworks is not a valid network"),
- sepolia => TokenDto(
- 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(
- 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(
- addresses: {chainId: wrappedNativeTokenAddress},
- decimals: NativeCurrencies.eth.currencyInfo.decimals,
- name: "Wrapped Ether",
- symbol: "WETH",
- logoUrl:
- "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/scroll/assets/0x5300000000000000000000000000000000000004/logo.png",
- ),
- // base => TokenDto(
- // addresses: {chainId: wrappedNativeTokenAddress},
- // decimals: NativeCurrencies.eth.currencyInfo.decimals,
- // name: "Wrapped Ether",
- // symbol: "WETH",
- // logoUrl:
- // "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/base/assets/0x4200000000000000000000000000000000000006/logo.png",
- // ),
- unichain => TokenDto(
- addresses: {chainId: wrappedNativeTokenAddress},
- decimals: NativeCurrencies.eth.currencyInfo.decimals,
- name: "Wrapped Ether",
- symbol: "WETH",
- logoUrl: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/unichain/logo.png",
- ),
+ unichain => "0x4200000000000000000000000000000000000006",
+ bnb => "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
};
String get rpcUrl => switch (this) {
@@ -163,6 +133,7 @@ enum AppNetworks {
scroll => "https://scroll-rpc.publicnode.com",
// base => "https://base-rpc.publicnode.com",
unichain => "https://unichain-rpc.publicnode.com",
+ bnb => "https://bsc-rpc.publicnode.com"
};
Future openTx(String txHash) async {
diff --git a/lib/core/enums/protocol_id.dart b/lib/core/enums/protocol_id.dart
new file mode 100644
index 0000000..529166a
--- /dev/null
+++ b/lib/core/enums/protocol_id.dart
@@ -0,0 +1,14 @@
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+part 'protocol_id.g.dart';
+
+@JsonEnum(alwaysCreate: true)
+enum ProtocolId {
+ @JsonValue("pancake-v4-cl")
+ pancakeSwapInfinityCL,
+ unknown;
+
+ bool get isPancakeSwapInfinityCL => this == ProtocolId.pancakeSwapInfinityCL;
+
+ String get toRawJsonValue => _$ProtocolIdEnumMap[this]!;
+}
diff --git a/lib/core/injections.dart b/lib/core/injections.dart
index 284f4e5..c4a2e38 100644
--- a/lib/core/injections.dart
+++ b/lib/core/injections.dart
@@ -7,6 +7,7 @@ import 'package:lottie/lottie.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:web3kit/web3kit.dart';
import 'package:zup_app/abis/erc_20.abi.g.dart';
+import 'package:zup_app/abis/pancake_swap_infinity_cl_pool_manager.abi.g.dart';
import 'package:zup_app/abis/uniswap_permit2.abi.g.dart';
import 'package:zup_app/abis/uniswap_v3_pool.abi.g.dart';
import 'package:zup_app/abis/uniswap_v3_position_manager.abi.g.dart';
@@ -121,14 +122,13 @@ Future setupInjections() async {
inject.registerLazySingleton(() => EthereumAbiCoder());
+ inject.registerLazySingleton(
+ () => PancakeSwapInfinityClPoolManager(),
+ );
+
inject.registerLazySingleton(
- () => PoolService(
- inject(),
- inject(),
- inject(),
- inject(),
- inject(),
- ),
+ () => PoolService(inject(), inject(), inject(),
+ inject(), inject(), inject()),
);
inject.registerLazySingleton(
diff --git a/lib/core/pool_service.dart b/lib/core/pool_service.dart
index 8a85d1a..f02deae 100644
--- a/lib/core/pool_service.dart
+++ b/lib/core/pool_service.dart
@@ -1,6 +1,7 @@
import 'package:clock/clock.dart';
import 'package:web3kit/core/dtos/transaction_response.dart';
import 'package:web3kit/web3kit.dart';
+import 'package:zup_app/abis/pancake_swap_infinity_cl_pool_manager.abi.g.dart';
import 'package:zup_app/abis/uniswap_v3_pool.abi.g.dart';
import 'package:zup_app/abis/uniswap_v3_position_manager.abi.g.dart';
import 'package:zup_app/abis/uniswap_v4_position_manager.abi.g.dart';
@@ -15,6 +16,7 @@ class PoolService with V4PoolLiquidityCalculationsMixin {
final UniswapV3PositionManager _uniswapV3PositionManager;
final UniswapV4PositionManager _uniswapV4PositionManager;
final EthereumAbiCoder _ethereumAbiCoder;
+ final PancakeSwapInfinityClPoolManager _pancakeSwapInfinityClPoolManager;
PoolService(
this._uniswapV4StateView,
@@ -22,9 +24,19 @@ class PoolService with V4PoolLiquidityCalculationsMixin {
this._uniswapV3PositionManager,
this._uniswapV4PositionManager,
this._ethereumAbiCoder,
+ this._pancakeSwapInfinityClPoolManager,
);
Future getPoolTick(YieldDto forYield) async {
+ if (forYield.protocol.id.isPancakeSwapInfinityCL) {
+ final pancakeSwapInfinityCLPoolManagerContract = _pancakeSwapInfinityClPoolManager.fromRpcProvider(
+ contractAddress: forYield.v4PoolManager!,
+ rpcUrl: forYield.network.rpcUrl,
+ );
+
+ return (await pancakeSwapInfinityCLPoolManagerContract.getSlot0(id: forYield.poolAddress)).tick;
+ }
+
if (forYield.poolType.isV4) {
final stateView = _uniswapV4StateView.fromRpcProvider(
contractAddress: forYield.v4StateView!,
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 83b566c..1e167ae 100644
--- a/test/app/create/create_page_select_token_stage_test.dart
+++ b/test/app/create/create_page_select_token_stage_test.dart
@@ -92,7 +92,7 @@ void main() {
"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 = AppNetworks.sepolia;
- final token0 = selectedNetwork.wrappedNative;
+ final token0 = TokenDto.fixture();
when(() => tokensRepository.getPopularTokens(any())).thenAnswer(
(_) async => [token0],
@@ -112,7 +112,7 @@ void main() {
"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 = AppNetworks.sepolia;
- final token0 = selectedNetwork.wrappedNative;
+ final token0 = TokenDto.fixture();
when(() => appCubit.currentChainId).thenReturn(selectedNetwork.chainId);
when(() => tokensRepository.getPopularTokens(any())).thenAnswer(
diff --git a/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price.png b/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price.png
index ad2038b..5aa5a7c 100644
Binary files a/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price.png and b/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price.png differ
diff --git a/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price_reversed.png b/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price_reversed.png
index 5c9e4af..5aa5a7c 100644
Binary files a/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price_reversed.png and b/test/app/create/deposit/widgets/goldens/range_selector_is_infinity_increase_price_reversed.png differ
diff --git a/test/app/create/deposit/widgets/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 7334694..d6da623 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
@@ -1004,8 +1004,8 @@ void main() {
tickLower: V3PoolConversorsMixinWrapper().tickToClosestValidTick(
tick: V3PoolConversorsMixinWrapper().priceToTick(
price: minPrice,
- poolToken0Decimals: currentYield.token0.decimals,
- poolToken1Decimals: currentYield.token1.decimals,
+ poolToken0Decimals: currentYield.token0NetworkDecimals,
+ poolToken1Decimals: currentYield.token1NetworkDecimals,
isReversed: false,
),
tickSpacing: currentYield.tickSpacing,
@@ -1052,8 +1052,8 @@ void main() {
tickLower: V3PoolConversorsMixinWrapper().tickToClosestValidTick(
tick: V3PoolConversorsMixinWrapper().priceToTick(
price: maxPrice,
- poolToken0Decimals: currentYield.token0.decimals,
- poolToken1Decimals: currentYield.token1.decimals,
+ poolToken0Decimals: currentYield.token0NetworkDecimals,
+ poolToken1Decimals: currentYield.token1NetworkDecimals,
isReversed: isReversed,
),
tickSpacing: currentYield.tickSpacing,
@@ -1177,8 +1177,8 @@ void main() {
tickUpper: V3PoolConversorsMixinWrapper().tickToClosestValidTick(
tick: V3PoolConversorsMixinWrapper().priceToTick(
price: maxPrice,
- poolToken0Decimals: currentYield.token0.decimals,
- poolToken1Decimals: currentYield.token1.decimals,
+ poolToken0Decimals: currentYield.token0NetworkDecimals,
+ poolToken1Decimals: currentYield.token1NetworkDecimals,
isReversed: false,
),
tickSpacing: currentYield.tickSpacing,
@@ -1224,8 +1224,8 @@ void main() {
tickUpper: V3PoolConversorsMixinWrapper().tickToClosestValidTick(
tick: V3PoolConversorsMixinWrapper().priceToTick(
price: minPrice,
- poolToken0Decimals: currentYield.token0.decimals,
- poolToken1Decimals: currentYield.token1.decimals,
+ poolToken0Decimals: currentYield.token0NetworkDecimals,
+ poolToken1Decimals: currentYield.token1NetworkDecimals,
isReversed: isReversed,
),
tickSpacing: currentYield.tickSpacing,
@@ -1702,8 +1702,8 @@ void main() {
verify(() => zupAnalytics.logDeposit(
depositedYield: currentYield,
- amount0Formatted: token0amount.parseTokenAmount(decimals: currentYield.token0.decimals),
- amount1Formatted: token1amount.parseTokenAmount(decimals: currentYield.token1.decimals),
+ amount0Formatted: token0amount.parseTokenAmount(decimals: currentYield.token0NetworkDecimals),
+ amount1Formatted: token1amount.parseTokenAmount(decimals: currentYield.token1NetworkDecimals),
walletAddress: userAddress,
)).called(1);
},
@@ -1936,16 +1936,16 @@ void main() {
final tickLower = V3PoolConversorsMixinWrapper().tickToClosestValidTick(
tick: V3PoolConversorsMixinWrapper().priceToTick(
price: minPrice,
- poolToken0Decimals: currentYield0.token0.decimals,
- poolToken1Decimals: currentYield0.token1.decimals,
+ poolToken0Decimals: currentYield0.token0NetworkDecimals,
+ poolToken1Decimals: currentYield0.token1NetworkDecimals,
),
tickSpacing: currentYield0.tickSpacing);
final tickUpper = V3PoolConversorsMixinWrapper().tickToClosestValidTick(
tick: V3PoolConversorsMixinWrapper().priceToTick(
price: maxPrice,
- poolToken0Decimals: currentYield0.token0.decimals,
- poolToken1Decimals: currentYield0.token1.decimals,
+ poolToken0Decimals: currentYield0.token0NetworkDecimals,
+ poolToken1Decimals: currentYield0.token1NetworkDecimals,
),
tickSpacing: currentYield0.tickSpacing);
diff --git a/test/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_test.dart b/test/app/create/deposit/widgets/preview_deposit_modal/preview_deposit_modal_test.dart
index 1581893..f96918d 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
@@ -309,8 +309,8 @@ void main() {
final currentPriceAsTick = V3PoolConversorsMixinWrapper().priceToTick(
price: currentPrice,
- poolToken0Decimals: currentYield.token0.decimals,
- poolToken1Decimals: currentYield.token1.decimals,
+ poolToken0Decimals: currentYield.token0NetworkDecimals,
+ poolToken1Decimals: currentYield.token1NetworkDecimals,
);
when(() => cubit.latestPoolTick).thenReturn(currentPriceAsTick);
@@ -335,8 +335,8 @@ void main() {
final currentPriceAsTick = V3PoolConversorsMixinWrapper().priceToTick(
price: currentPrice,
- poolToken0Decimals: currentYield.token0.decimals,
- poolToken1Decimals: currentYield.token1.decimals,
+ poolToken0Decimals: currentYield.token0NetworkDecimals,
+ poolToken1Decimals: currentYield.token1NetworkDecimals,
);
when(() => cubit.latestPoolTick).thenReturn(currentPriceAsTick);
@@ -364,8 +364,8 @@ void main() {
final currentPriceAsTick = V3PoolConversorsMixinWrapper().priceToTick(
price: currentPrice,
- poolToken0Decimals: currentYield.token0.decimals,
- poolToken1Decimals: currentYield.token1.decimals,
+ poolToken0Decimals: currentYield.token0NetworkDecimals,
+ poolToken1Decimals: currentYield.token1NetworkDecimals,
);
when(() => cubit.latestPoolTick).thenReturn(currentPriceAsTick);
@@ -541,7 +541,7 @@ void main() {
verify(
() => cubit.approveToken(
currentYield.token0,
- depositAmount.parseTokenAmount(decimals: currentYield.token0.decimals),
+ depositAmount.parseTokenAmount(decimals: currentYield.token0NetworkDecimals),
),
).called(1);
},
@@ -558,14 +558,14 @@ void main() {
when(() => cubit.state).thenReturn(
PreviewDepositModalState.initial(
- token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0.decimals),
+ token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0NetworkDecimals),
token1Allowance: token1Allowance,
),
);
when(() => cubit.stream).thenAnswer((_) {
return Stream.value(PreviewDepositModalState.initial(
- token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0.decimals),
+ token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0NetworkDecimals),
token1Allowance: token1Allowance,
));
});
@@ -593,14 +593,14 @@ void main() {
when(() => cubit.state).thenReturn(
PreviewDepositModalState.initial(
- token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0.decimals),
+ token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0NetworkDecimals),
token1Allowance: token1Allowance,
),
);
when(() => cubit.stream).thenAnswer((_) {
return Stream.value(PreviewDepositModalState.initial(
- token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0.decimals),
+ token0Allowance: depositAmount.parseTokenAmount(decimals: currentYield.token0NetworkDecimals),
token1Allowance: token1Allowance,
));
});
@@ -617,7 +617,7 @@ void main() {
verify(
() => cubit.approveToken(
currentYield.token1,
- depositAmount.parseTokenAmount(decimals: currentYield.token1.decimals),
+ depositAmount.parseTokenAmount(decimals: currentYield.token1NetworkDecimals),
),
).called(1);
},
@@ -629,8 +629,8 @@ void main() {
in the deposit state""",
goldenFileName: "preview_deposit_modal_deposit_state",
(tester) async {
- final token0Allowance = 400.parseTokenAmount(decimals: currentYield.token0.decimals);
- final token1Allowance = 1200.parseTokenAmount(decimals: currentYield.token1.decimals);
+ final token0Allowance = 400.parseTokenAmount(decimals: currentYield.token0NetworkDecimals);
+ final token1Allowance = 1200.parseTokenAmount(decimals: currentYield.token1NetworkDecimals);
const deposit0Amount = 100.2;
const deposit1Amount = 110.2;
@@ -663,8 +663,8 @@ void main() {
in the deposit state. Once the deposit button is clicked, it should call
the deposit function in the cubit passing the correct params (got from the constructor)""",
(tester) async {
- final token0Allowance = 400.parseTokenAmount(decimals: currentYield.token0.decimals);
- final token1Allowance = 1200.parseTokenAmount(decimals: currentYield.token1.decimals);
+ final token0Allowance = 400.parseTokenAmount(decimals: currentYield.token0NetworkDecimals);
+ final token1Allowance = 1200.parseTokenAmount(decimals: currentYield.token1NetworkDecimals);
const deposit0Amount = 100.2;
const deposit1Amount = 110.2;
@@ -716,8 +716,8 @@ void main() {
maxPrice: maxPrice,
minPrice: minPrice,
slippage: slippage,
- token0Amount: deposit0Amount.parseTokenAmount(decimals: currentYield.token0.decimals),
- token1Amount: deposit1Amount.parseTokenAmount(decimals: currentYield.token1.decimals),
+ token0Amount: deposit0Amount.parseTokenAmount(decimals: currentYield.token0NetworkDecimals),
+ token1Amount: deposit1Amount.parseTokenAmount(decimals: currentYield.token1NetworkDecimals),
),
).called(1);
},
@@ -730,8 +730,8 @@ void main() {
when(() => cubit.latestPoolTick).thenReturn(
V3PoolConversorsMixinWrapper().priceToTick(
price: 0.01, // It should be shown in the card (or very close to it)
- poolToken0Decimals: currentYield.token0.decimals,
- poolToken1Decimals: currentYield.token1.decimals,
+ poolToken0Decimals: currentYield.token0NetworkDecimals,
+ poolToken1Decimals: currentYield.token1NetworkDecimals,
isReversed: false,
),
);
@@ -748,8 +748,8 @@ void main() {
when(() => cubit.latestPoolTick).thenReturn(
V3PoolConversorsMixinWrapper().priceToTick(
price: 1200, // It should be shown in the card (or very close to it)
- poolToken0Decimals: currentYield.token0.decimals,
- poolToken1Decimals: currentYield.token1.decimals,
+ poolToken0Decimals: currentYield.token0NetworkDecimals,
+ poolToken1Decimals: currentYield.token1NetworkDecimals,
isReversed: true,
),
);
@@ -768,8 +768,8 @@ void main() {
const newPrice = 0.02632; // It should be shown in the card (or very close to it)
final newPriceAsTick = V3PoolConversorsMixinWrapper().priceToTick(
price: newPrice,
- poolToken0Decimals: currentYield.token0.decimals,
- poolToken1Decimals: currentYield.token1.decimals,
+ poolToken0Decimals: currentYield.token0NetworkDecimals,
+ poolToken1Decimals: currentYield.token1NetworkDecimals,
isReversed: false,
);
diff --git a/test/app/create/deposit/widgets/range_selector_test.dart b/test/app/create/deposit/widgets/range_selector_test.dart
index 00d56cb..2464733 100644
--- a/test/app/create/deposit/widgets/range_selector_test.dart
+++ b/test/app/create/deposit/widgets/range_selector_test.dart
@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:golden_toolkit/golden_toolkit.dart';
import 'package:zup_app/app/create/deposit/widgets/range_selector.dart';
-import 'package:zup_app/core/dtos/token_dto.dart';
import '../../../../golden_config.dart';
@@ -11,8 +10,8 @@ void main() {
Key? key,
bool isReversed = false,
Function(double price)? onPriceChanged,
- TokenDto? poolToken0,
- TokenDto? poolToken1,
+ int? poolToken0Decimals,
+ int? poolToken1Decimals,
int tickSpacing = 10,
RangeSelectorType type = RangeSelectorType.minPrice,
double? initialPrice,
@@ -32,8 +31,8 @@ void main() {
displayQuoteTokenSymbol: "Token B",
isReversed: isReversed,
onPriceChanged: onPriceChanged ?? (_) {},
- poolToken0: poolToken0 ?? TokenDto.fixture().copyWith(symbol: "Token A"),
- poolToken1: poolToken1 ?? TokenDto.fixture().copyWith(symbol: "Token B"),
+ poolToken0Decimals: poolToken0Decimals ?? 18,
+ poolToken1Decimals: poolToken0Decimals ?? 18,
tickSpacing: tickSpacing,
type: type,
initialPrice: initialPrice,
@@ -58,11 +57,7 @@ void main() {
zGoldenTest("When the `isReversed` param is true, it should reverse the tokens in the widget",
goldenFileName: "range_selector_reversed", (tester) async {
return tester.pumpDeviceBuilder(
- await goldenBuilder(
- isReversed: true,
- poolToken0: TokenDto.fixture().copyWith(symbol: "Token 0"),
- poolToken1: TokenDto.fixture().copyWith(symbol: "Token 1"),
- ),
+ await goldenBuilder(isReversed: true),
);
});
@@ -304,13 +299,13 @@ void main() {
"When the price is infinity, and click to increase, the price should increase to the minimum price based on the tick spacing",
goldenFileName: "range_selector_is_infinity_increase_price",
(tester) async {
- const expectedIncreasedPrice = 1.0010004501200209e-12;
+ const expectedIncreasedPrice = 9.996040641477102e-19;
double actualIncreasedPrice = 0;
await tester.pumpDeviceBuilder(await goldenBuilder(
isInfinity: true,
- poolToken0: TokenDto.fixture().copyWith(decimals: 6),
- poolToken1: TokenDto.fixture().copyWith(decimals: 18),
+ poolToken0Decimals: 6,
+ poolToken1Decimals: 18,
onPriceChanged: (price) {
actualIncreasedPrice = price;
},
@@ -328,14 +323,14 @@ void main() {
the price should increase to the minimum price based on the tick spacing""",
goldenFileName: "range_selector_is_infinity_increase_price_reversed",
(tester) async {
- const expectedIncreasedPrice = 1.0008055719626048e-12;
+ const expectedIncreasedPrice = 9.996040641477102e-19;
double actualIncreasedPrice = 0;
await tester.pumpDeviceBuilder(await goldenBuilder(
isInfinity: true,
isReversed: true,
- poolToken0: TokenDto.fixture().copyWith(decimals: 6),
- poolToken1: TokenDto.fixture().copyWith(decimals: 18),
+ poolToken0Decimals: 6,
+ poolToken1Decimals: 18,
onPriceChanged: (price) {
actualIncreasedPrice = price;
},
@@ -359,8 +354,8 @@ void main() {
await tester.pumpDeviceBuilder(await goldenBuilder(
isInfinity: true,
isReversed: true,
- poolToken0: TokenDto.fixture().copyWith(decimals: 6),
- poolToken1: TokenDto.fixture().copyWith(decimals: 18),
+ poolToken0Decimals: 6,
+ poolToken1Decimals: 18,
onPriceChanged: (price) {
actualIncreasedPrice = price;
},
@@ -382,8 +377,8 @@ void main() {
await tester.pumpDeviceBuilder(await goldenBuilder(
isInfinity: true,
- poolToken0: TokenDto.fixture().copyWith(decimals: 6),
- poolToken1: TokenDto.fixture().copyWith(decimals: 18),
+ poolToken0Decimals: 6,
+ poolToken1Decimals: 18,
onPriceChanged: (price) {
actualIncreasedPrice = price;
},
diff --git a/test/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button_test.dart b/test/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button_test.dart
index 7b4c942..073d8ae 100644
--- a/test/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button_test.dart
+++ b/test/app/create/widgets/exchanges_filter_dropdown_button/exchanges_filter_dropdown_button_test.dart
@@ -68,10 +68,10 @@ void main() {
when(() => cache.blockedProtocolsIds).thenReturn(blockedProtocolsIds);
when(() => protocolRepository.getAllSupportedProtocols()).thenAnswer((_) async => [
- ProtocolDto(name: "C", id: blockedProtocolsIds[0]),
- ProtocolDto(name: "A", id: blockedProtocolsIds[1]),
- ProtocolDto(name: "B", id: blockedProtocolsIds[2]),
- const ProtocolDto(name: "A", id: "some other id not blocked"),
+ ProtocolDto(name: "C", rawId: blockedProtocolsIds[0]),
+ ProtocolDto(name: "A", rawId: blockedProtocolsIds[1]),
+ ProtocolDto(name: "B", rawId: blockedProtocolsIds[2]),
+ const ProtocolDto(name: "A", rawId: "some other id not blocked"),
]);
await tester.pumpDeviceBuilder(await goldenBuilder());
@@ -90,7 +90,6 @@ void main() {
await tester.pumpAndSettle();
},
);
-
zGoldenTest(
"""When the cubit state is error, and the user clicks the button,
it should show a snackbar saying to try to refresh the page""",
@@ -139,10 +138,10 @@ void main() {
when(() => protocolRepository.getAllSupportedProtocols()).thenAnswer(
(_) async => [
- ProtocolDto(name: "A", id: blockedProtocolsIds[0]),
- const ProtocolDto(name: "B", id: "some other id not blocked"),
- ProtocolDto(name: "C", id: blockedProtocolsIds[2]),
- const ProtocolDto(name: "D", id: "some other id not blocked"),
+ ProtocolDto(name: "A", rawId: blockedProtocolsIds[0]),
+ const ProtocolDto(name: "B", rawId: "some other id not blocked"),
+ ProtocolDto(name: "C", rawId: blockedProtocolsIds[2]),
+ const ProtocolDto(name: "D", rawId: "some other id not blocked"),
],
);
@@ -161,10 +160,10 @@ void main() {
(tester) async {
final blockedProtocolsIds = ["32983", "sag", "nnnn", "dale"];
final allProtocols = [
- ProtocolDto(name: "A", id: blockedProtocolsIds[0]),
- const ProtocolDto(name: "B", id: "some other id not blocked"),
- ProtocolDto(name: "C", id: blockedProtocolsIds[2]),
- const ProtocolDto(name: "D", id: "some other id not blocked"),
+ ProtocolDto(name: "A", rawId: blockedProtocolsIds[0]),
+ const ProtocolDto(name: "B", rawId: "some other id not blocked"),
+ ProtocolDto(name: "C", rawId: blockedProtocolsIds[2]),
+ const ProtocolDto(name: "D", rawId: "some other id not blocked"),
];
when(() => cache.saveBlockedProtocolIds(blockedProtocolIds: any(named: "blockedProtocolIds"))).thenAnswer(
@@ -199,10 +198,10 @@ void main() {
(tester) async {
final blockedProtocolsIds = ["32983", "sag", "nnnn", "dale"];
final allProtocols = [
- ProtocolDto(name: "A", id: blockedProtocolsIds[0]),
- const ProtocolDto(name: "B", id: "some other id not blocked"),
- ProtocolDto(name: "C", id: blockedProtocolsIds[2]),
- const ProtocolDto(name: "D", id: "some other id not blocked"),
+ ProtocolDto(name: "A", rawId: blockedProtocolsIds[0]),
+ const ProtocolDto(name: "B", rawId: "some other id not blocked"),
+ ProtocolDto(name: "C", rawId: blockedProtocolsIds[2]),
+ const ProtocolDto(name: "D", rawId: "some other id not blocked"),
];
when(() => cache.saveBlockedProtocolIds(blockedProtocolIds: any(named: "blockedProtocolIds"))).thenAnswer(
diff --git a/test/app/create/widgets/exchanges_filter_dropdown_button/goldens/exchanges_filter_dropdown_button_error_click.png b/test/app/create/widgets/exchanges_filter_dropdown_button/goldens/exchanges_filter_dropdown_button_error_click.png
index e03da5b..cf703ac 100644
Binary files a/test/app/create/widgets/exchanges_filter_dropdown_button/goldens/exchanges_filter_dropdown_button_error_click.png and b/test/app/create/widgets/exchanges_filter_dropdown_button/goldens/exchanges_filter_dropdown_button_error_click.png differ
diff --git a/test/core/enums/goldens/bnb_network_icon.png b/test/core/enums/goldens/bnb_network_icon.png
new file mode 100644
index 0000000..198aeeb
Binary files /dev/null and b/test/core/enums/goldens/bnb_network_icon.png differ
diff --git a/test/core/enums/networks_test.dart b/test/core/enums/networks_test.dart
index 41fa609..d0ca826 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:zup_app/core/dtos/token_dto.dart';
import 'package:zup_app/core/enums/networks.dart';
import '../../golden_config.dart';
@@ -24,6 +23,7 @@ void main() {
expect(AppNetworks.fromValue("allNetworks"), AppNetworks.allNetworks, reason: "All networks should match");
// expect(AppNetworks.fromValue("base"), AppNetworks.base, reason: "Base should match");
expect(AppNetworks.fromValue("unichain"), AppNetworks.unichain, reason: "Unichain should match");
+ expect(AppNetworks.fromValue("bnb"), AppNetworks.bnb, reason: "BNB should match");
});
test("Label extension should match for all networks", () {
@@ -33,6 +33,7 @@ void main() {
expect(AppNetworks.allNetworks.label, "All Networks", reason: "All Networks Label should match");
// expect(AppNetworks.base.label, "Base", reason: "Base Label should match");
expect(AppNetworks.unichain.label, "Unichain", reason: "Unichain Label should match");
+ expect(AppNetworks.bnb.label, "BNB Chain", reason: "BNB Chain Label should match");
});
test("`testnets` method should return all testnets in the enum, excluding the 'all networks'", () {
@@ -48,6 +49,7 @@ void main() {
AppNetworks.scroll,
// AppNetworks.base,
AppNetworks.unichain,
+ AppNetworks.bnb
]),
);
});
@@ -72,6 +74,10 @@ void main() {
expect(AppNetworks.unichain.isTestnet, false);
});
+ test("`isTestnet` method should return false for bnb", () {
+ expect(AppNetworks.bnb.isTestnet, false);
+ });
+
test("Chain info extension should match for all networks", () {
expect(
AppNetworks.sepolia.chainInfo,
@@ -125,12 +131,24 @@ void main() {
ChainInfo(
hexChainId: "0x82",
chainName: "Unichain",
- blockExplorerUrls: const ["https://uniscan.xyz/"],
+ blockExplorerUrls: const ["https://uniscan.xyz"],
nativeCurrency: NativeCurrencies.eth.currencyInfo,
rpcUrls: const ["https://unichain-rpc.publicnode.com"],
),
reason: "Unichain ChainInfo should match",
);
+
+ expect(
+ AppNetworks.bnb.chainInfo,
+ ChainInfo(
+ hexChainId: "0x38",
+ chainName: "BNB Chain",
+ blockExplorerUrls: const ["https://bscscan.com"],
+ nativeCurrency: NativeCurrencies.bnb.currencyInfo,
+ rpcUrls: const ["https://bsc-rpc.publicnode.com"],
+ ),
+ reason: "BNB Chain ChainInfo should match",
+ );
});
test("wrapped native token address should match for all networks", () {
@@ -165,80 +183,6 @@ void main() {
);
});
- test("wrapped native token should match for all networks", () {
- expect(
- AppNetworks.sepolia.wrappedNative,
- TokenDto(
- addresses: {
- AppNetworks.sepolia.chainId: "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14",
- },
- name: "Wrapped Ether",
- decimals: 18,
- symbol: "WETH",
- logoUrl: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/info/logo.png",
- ),
- reason: "Sepolia default token should match",
- );
-
- expect(
- AppNetworks.mainnet.wrappedNative,
- TokenDto(
- addresses: {
- AppNetworks.mainnet.chainId: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
- },
- name: "Wrapped Ether",
- decimals: 18,
- symbol: "WETH",
- logoUrl: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/info/logo.png",
- ),
- reason: "Ethereum default token should match",
- );
-
- expect(
- AppNetworks.scroll.wrappedNative,
- TokenDto(
- addresses: {
- AppNetworks.scroll.chainId: "0x5300000000000000000000000000000000000004",
- },
- name: "Wrapped Ether",
- decimals: 18,
- symbol: "WETH",
- logoUrl:
- "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/scroll/assets/0x5300000000000000000000000000000000000004/logo.png",
- ),
- reason: "Scroll default token should match",
- );
-
- // expect(
- // AppNetworks.base.wrappedNative,
- // TokenDto(
- // addresses: {
- // AppNetworks.base.chainId: "0x4200000000000000000000000000000000000006",
- // },
- // name: "Wrapped Ether",
- // decimals: 18,
- // symbol: "WETH",
- // logoUrl:
- // "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/base/assets/0x4200000000000000000000000000000000000006/logo.png",
- // ),
- // reason: "Base default token should match",
- // );
-
- expect(
- AppNetworks.unichain.wrappedNative,
- TokenDto(
- addresses: {
- AppNetworks.unichain.chainId: "0x4200000000000000000000000000000000000006",
- },
- name: "Wrapped Ether",
- decimals: 18,
- symbol: "WETH",
- logoUrl: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/unichain/logo.png",
- ),
- reason: "Unichain default token should match",
- );
- });
-
test("RpcUrl extension should return the correct rpc url", () {
expect(
AppNetworks.sepolia.rpcUrl,
@@ -269,6 +213,12 @@ void main() {
"https://unichain-rpc.publicnode.com",
reason: "Unichain rpc url should match",
);
+
+ expect(
+ AppNetworks.bnb.rpcUrl,
+ "https://bsc-rpc.publicnode.com",
+ reason: "BNB rpc url should match",
+ );
});
test("openTx should open the correct url for each network", () async {
@@ -350,4 +300,11 @@ void main() {
device: GoldenDevice.square,
));
});
+
+ zGoldenTest("BNB network icon should match", goldenFileName: "bnb_network_icon", (tester) async {
+ await tester.pumpDeviceBuilder(await goldenDeviceBuilder(
+ AppNetworks.bnb.icon,
+ device: GoldenDevice.square,
+ ));
+ });
}
diff --git a/test/core/enums/protocol_id_test.dart b/test/core/enums/protocol_id_test.dart
new file mode 100644
index 0000000..b2d22a2
--- /dev/null
+++ b/test/core/enums/protocol_id_test.dart
@@ -0,0 +1,18 @@
+import 'package:flutter_test/flutter_test.dart';
+import 'package:zup_app/core/enums/protocol_id.dart';
+
+void main() {
+ test(
+ "When calling `isPancakeSwapInfinityCL` and the protocol is indeed pancakeSwapInfinityCL, it should return true",
+ () {
+ expect(ProtocolId.pancakeSwapInfinityCL.isPancakeSwapInfinityCL, true);
+ },
+ );
+
+ test(
+ "When calling `isPancakeSwapInfinityCL` and the protocol is not pancakeSwapInfinityCL, it should return false",
+ () {
+ expect(ProtocolId.unknown.isPancakeSwapInfinityCL, false);
+ },
+ );
+}
diff --git a/test/core/pool_service_test.dart b/test/core/pool_service_test.dart
index c19d037..e511d08 100644
--- a/test/core/pool_service_test.dart
+++ b/test/core/pool_service_test.dart
@@ -4,14 +4,17 @@ import 'package:mocktail/mocktail.dart';
import 'package:web3kit/core/dtos/transaction_receipt.dart';
import 'package:web3kit/core/dtos/transaction_response.dart';
import 'package:web3kit/web3kit.dart';
+import 'package:zup_app/abis/pancake_swap_infinity_cl_pool_manager.abi.g.dart';
import 'package:zup_app/abis/uniswap_v3_pool.abi.g.dart';
import 'package:zup_app/abis/uniswap_v3_position_manager.abi.g.dart';
import 'package:zup_app/abis/uniswap_v4_position_manager.abi.g.dart';
import 'package:zup_app/abis/uniswap_v4_state_view.abi.g.dart';
+import 'package:zup_app/core/dtos/protocol_dto.dart';
import 'package:zup_app/core/dtos/token_dto.dart';
import 'package:zup_app/core/dtos/yield_dto.dart';
import 'package:zup_app/core/enums/networks.dart';
import 'package:zup_app/core/enums/pool_type.dart';
+import 'package:zup_app/core/enums/protocol_id.dart';
import 'package:zup_app/core/mixins/v4_pool_liquidity_calculations_mixin.dart';
import 'package:zup_app/core/pool_service.dart';
import 'package:zup_app/core/v4_pool_constants.dart';
@@ -26,6 +29,7 @@ void main() {
late UniswapV3Pool uniswapV3Pool;
late UniswapV3PositionManager positionManagerV3;
late UniswapV4PositionManager positionManagerV4;
+ late PancakeSwapInfinityClPoolManager pancakeSwapInfinityCLPoolManager;
late Signer signer;
late YieldDto currentYield;
late TransactionResponse transactionResponse;
@@ -34,6 +38,7 @@ void main() {
late UniswapV3PoolImpl uniswapV3PoolImpl;
late UniswapV3PositionManagerImpl positionManagerV3Impl;
late UniswapV4PositionManagerImpl positionManagerV4Impl;
+ late PancakeSwapInfinityClPoolManagerImpl pancakeSwapInfinityCLPoolManagerImpl;
late EthereumAbiCoder ethereumAbiCoder;
setUp(() {
@@ -58,9 +63,12 @@ void main() {
uniswapV3Pool = UniswapV3PoolMock();
positionManagerV3 = UniswapV3PositionManagerMock();
positionManagerV4 = UniswapV4PositionManagerMock();
+ pancakeSwapInfinityCLPoolManager = PancakeSwapInfinityCLPoolManagerMock();
ethereumAbiCoder = EthereumAbiCoderMock();
signer = SignerMock();
+ pancakeSwapInfinityCLPoolManagerImpl = PancakeSwapInfinityCLPoolManagerImplMock();
+
stateViewImpl = UniswapV4StateViewImplMock();
uniswapV3PoolImpl = UniswapV3PoolImplMock();
positionManagerV3Impl = UniswapV3PositionManagerImplMock();
@@ -68,7 +76,14 @@ void main() {
currentYield = YieldDto.fixture();
- sut = PoolService(stateView, uniswapV3Pool, positionManagerV3, positionManagerV4, ethereumAbiCoder);
+ sut = PoolService(
+ stateView,
+ uniswapV3Pool,
+ positionManagerV3,
+ positionManagerV4,
+ ethereumAbiCoder,
+ pancakeSwapInfinityCLPoolManager,
+ );
when(() => stateView.fromRpcProvider(contractAddress: any(named: "contractAddress"), rpcUrl: any(named: "rpcUrl")))
.thenReturn(stateViewImpl);
@@ -110,6 +125,12 @@ void main() {
sqrtPriceX96: BigInt.from(0),
tick: expectedTick,
));
+ when(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: any(named: "id"))).thenAnswer((_) async => (
+ lpFee: BigInt.from(0),
+ protocolFee: BigInt.from(0),
+ sqrtPriceX96: BigInt.from(0),
+ tick: expectedTick,
+ ));
final currentYield0 = currentYield.copyWith(poolType: PoolType.v4, v4StateView: "0x123");
final result = await sut.getPoolTick(currentYield0);
@@ -254,7 +275,7 @@ void main() {
recipient: recipient,
tickLower: tickLower,
tickUpper: tickUpper,
- token0: network.wrappedNative.addresses[network.chainId]!,
+ token0: network.wrappedNativeTokenAddress,
token1: token1Address,
)),
).called(1);
@@ -1331,4 +1352,34 @@ void main() {
).called(1);
},
);
+
+ test(
+ """"When calling `getPoolTick` and the yield protocol is pancakeswap infinity cl,
+ it should use the pancakeswap inifity cl pool manager to get the tick""",
+ () async {
+ final expectedTick = BigInt.from(318675);
+
+ when(() => pancakeSwapInfinityCLPoolManager.fromRpcProvider(
+ contractAddress: any(named: "contractAddress"), rpcUrl: any(named: "rpcUrl"))).thenReturn(
+ pancakeSwapInfinityCLPoolManagerImpl,
+ );
+
+ when(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: any(named: "id"))).thenAnswer((_) async => (
+ sqrtPriceX96: BigInt.from(0),
+ tick: expectedTick,
+ protocolFee: BigInt.from(0),
+ lpFee: BigInt.from(0),
+ ));
+
+ final yield0 = currentYield.copyWith(
+ protocol: ProtocolDto.fixture().copyWith(id: ProtocolId.pancakeSwapInfinityCL),
+ v4PoolManager: "0x0000001",
+ );
+
+ final receivedPoolTick = await sut.getPoolTick(yield0);
+ expect(receivedPoolTick, expectedTick);
+
+ verify(() => pancakeSwapInfinityCLPoolManagerImpl.getSlot0(id: yield0.poolAddress)).called(1);
+ },
+ );
}
diff --git a/test/core/repositories/protocol_repository_test.dart b/test/core/repositories/protocol_repository_test.dart
index 79a8cf2..a0cf821 100644
--- a/test/core/repositories/protocol_repository_test.dart
+++ b/test/core/repositories/protocol_repository_test.dart
@@ -31,12 +31,13 @@ void main() {
test("When calling `getAllSupportedProtocols` it should return a list of protocols", () async {
final protocols = [
- ProtocolDto.fixture().copyWith(id: "1", name: "LULU", logo: "LALA.png", url: "LALA.com"),
- ProtocolDto.fixture().copyWith(id: "2", name: "LALA", logo: "LULU.png", url: "LULU.com"),
+ ProtocolDto.fixture().copyWith(rawId: "1", name: "LULU", logo: "LALA.png", url: "LALA.com"),
+ ProtocolDto.fixture().copyWith(rawId: "2", name: "LALA", logo: "LULU.png", url: "LULU.com"),
];
+
when(() => zupApiDio.get(any())).thenAnswer(
(_) async => Response(
- data: protocols.map((protocol) => protocol.toJson()).toList(),
+ data: protocols.map((protocol) => protocol.toJson()..["id"] = protocol.rawId.toString()).toList(),
statusCode: 200,
requestOptions: RequestOptions(),
),
diff --git a/test/mocks.dart b/test/mocks.dart
index ecbade7..38d52f0 100644
--- a/test/mocks.dart
+++ b/test/mocks.dart
@@ -12,6 +12,7 @@ import 'package:url_launcher_platform_interface/url_launcher_platform_interface.
import 'package:web3kit/core/dtos/transaction_response.dart';
import 'package:web3kit/web3kit.dart';
import 'package:zup_app/abis/erc_20.abi.g.dart';
+import 'package:zup_app/abis/pancake_swap_infinity_cl_pool_manager.abi.g.dart';
import 'package:zup_app/abis/uniswap_permit2.abi.g.dart';
import 'package:zup_app/abis/uniswap_v3_pool.abi.g.dart';
import 'package:zup_app/abis/uniswap_v3_position_manager.abi.g.dart';
@@ -88,6 +89,10 @@ class UniswapV4PositionManagerMock extends Mock implements UniswapV4PositionMana
class UniswapV4PositionManagerImplMock extends Mock implements UniswapV4PositionManagerImpl {}
+class PancakeSwapInfinityCLPoolManagerMock extends Mock implements PancakeSwapInfinityClPoolManager {}
+
+class PancakeSwapInfinityCLPoolManagerImplMock extends Mock implements PancakeSwapInfinityClPoolManagerImpl {}
+
class UniswapV3PoolImplMock extends Mock implements UniswapV3PoolImpl {}
class UniswapV3PoolMock extends Mock implements UniswapV3Pool {}
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 3f2868a..0ac65fb 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
@@ -279,8 +279,8 @@ void main() {
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: {}),
+ TokenDto.fixture().copyWith(name: "", symbol: "", logoUrl: "", addresses: {}),
+ TokenDto.fixture().copyWith(name: "", symbol: "", decimals: {}, logoUrl: "", addresses: {}),
];
when(() => tokensRepository.searchToken(any(), any())).thenAnswer((_) async => returnedList);
@@ -294,8 +294,8 @@ void main() {
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: {}),
+ TokenDto.fixture().copyWith(name: "", symbol: "", logoUrl: "", addresses: {}),
+ TokenDto.fixture().copyWith(name: "", symbol: "", logoUrl: "", addresses: {}),
namedToken,
];