dev
dart 141 lines 4.5 KB
Raw
1 import "package:cake_wallet/core/address_validator.dart";
2 import "package:cake_wallet/core/anypay/anypay_models.dart";
3 import "package:cake_wallet/reactions/wallet_connect.dart";
4 import "package:cw_core/crypto_currency.dart";
5 import "package:cw_core/wallet_type.dart";
6
7 class AnyPayRouter {
8 static final List<RegExp> _swapIncompatibleAddressPatterns = [
9 RegExp("^(?:${AddressValidator.silentPaymentAddressPatternMainnet})\$"),
10 RegExp("^(?:${AddressValidator.silentPaymentAddressPatternTestnet})\$"),
11 RegExp("^(?:${AddressValidator.mWebAddressPattern})\$"),
12 ];
13
14 static bool _isSwapIncompatibleAddress(String address) =>
15 _swapIncompatibleAddressPatterns.any((pattern) => pattern.hasMatch(address));
16
17 static AnyPayDecision route(
18 AnyPayRequest request,
19 WalletSnapshot snapshot,
20 AnyPayResolution resolution,
21 ) {
22 if (request.rawInput.trim().isEmpty) {
23 return const AnyPayEmptyInput();
24 }
25
26 final detection = request.detection;
27 final detectedType = detection.detectedWalletType;
28
29 if (!detection.isValid || detectedType == null) {
30 return const AnyPayApplyToCurrentWallet();
31 }
32
33 if (detectedType == WalletType.solana && !snapshot.hasSolanaProxy) {
34 return const AnyPayApplyToCurrentWallet();
35 }
36
37 if (detectedType == WalletType.tron && !snapshot.hasTronProxy) {
38 return const AnyPayApplyToCurrentWallet();
39 }
40
41 if (isEVMCompatibleChain(detectedType)) {
42 if (!snapshot.hasEvmProxy) {
43 return const AnyPayApplyToCurrentWallet();
44 }
45
46 return _routeEvm(request, snapshot, resolution);
47 }
48
49 if (resolution is TokenUnknown) {
50 return AnyPayUnsupportedToken(resolution.contract);
51 }
52
53 if (detectedType == snapshot.type) {
54 return AnyPayApplyToCurrentWallet(
55 token: resolution is TokenResolved ? resolution.token : null,
56 amountOverride: resolution is TokenResolved ? resolution.amountOverride : null,
57 fallbackCurrency: _nativeRequestCurrency(request),
58 );
59 }
60
61 return AnyPayCrossChainPayment(
62 targetWalletType: detectedType,
63 wallets: snapshot.walletsOfType(detectedType),
64 token: resolution is TokenResolved ? resolution.token : null,
65 amountOverride: resolution is TokenResolved ? resolution.amountOverride : null,
66 canSwap: !_isSwapIncompatibleAddress(request.address),
67 );
68 }
69
70 static AnyPayDecision _routeEvm(
71 AnyPayRequest request,
72 WalletSnapshot snapshot,
73 AnyPayResolution resolution,
74 ) {
75 final requestedChainId = requestedEvmChainId(request, snapshot);
76
77 if (requestedChainId == null) {
78 if (snapshot.currentWalletIsEvm) {
79 return const AnyPayApplyToCurrentWallet();
80 }
81
82 return const AnyPayEvmNetworkChoice();
83 }
84
85 if (!snapshot.supportedEvmChains.containsKey(requestedChainId)) {
86 return AnyPayUnsupportedNetwork(requestedChainId);
87 }
88
89 if (resolution is TokenUnknown) {
90 return AnyPayUnsupportedToken(resolution.contract);
91 }
92
93 int targetChainId = requestedChainId;
94 if (resolution is TokenResolved && resolution.chainId != null) {
95 targetChainId = resolution.chainId!;
96 }
97
98 final token = resolution is TokenResolved ? resolution.token : null;
99 final amountOverride = resolution is TokenResolved ? resolution.amountOverride : null;
100
101 if (snapshot.currentWalletIsEvm && snapshot.currentChainId == targetChainId) {
102 return AnyPayApplyToCurrentWallet(
103 token: token,
104 amountOverride: amountOverride,
105 fallbackCurrency: _nativeRequestCurrency(request),
106 );
107 }
108
109 final targetWalletType = snapshot.supportedEvmChains[targetChainId]!;
110
111 return AnyPayCrossChainPayment(
112 targetWalletType: targetWalletType,
113 targetChainId: targetChainId,
114 wallets: snapshot.walletsOfType(targetWalletType),
115 token: token,
116 amountOverride: amountOverride,
117 );
118 }
119
120 static CryptoCurrency? _nativeRequestCurrency(AnyPayRequest request) {
121 if (request.paymentRequest.scheme.isEmpty || request.hasContract || request.amount.isEmpty) {
122 return null;
123 }
124 return request.detection.detectedCurrency;
125 }
126
127 static int? requestedEvmChainId(AnyPayRequest request, WalletSnapshot snapshot) {
128 final binding = request.chainBinding;
129
130 if (binding is ExplicitEvmChain) {
131 return binding.chainId;
132 }
133
134 if (binding is ChainlessEvm) {
135 // the eip 681 spec says we should use the current chain id if there is no chainId in the incoming request
136 return snapshot.currentWalletIsEvm ? snapshot.currentChainId ?? 1 : 1;
137 }
138
139 return null;
140 }
141 }