dev
dart 109 lines 3.5 KB
Raw
1 import "package:cake_wallet/core/anypay/anypay_models.dart";
2 import "package:cake_wallet/core/anypay/anypay_router.dart";
3 import "package:cake_wallet/reactions/wallet_connect.dart";
4 import "package:cake_wallet/utils/token_utilities.dart";
5 import "package:cw_core/crypto_currency.dart";
6 import "package:cw_core/wallet_type.dart";
7
8 class AnyPayResolver {
9 AnyPayResolver({AnyPayTokenLookup? tokenLookup})
10 : _tokenLookup = tokenLookup ?? const TokenUtilitiesLookup();
11
12 final AnyPayTokenLookup _tokenLookup;
13
14 Future<AnyPayResolution> resolve(AnyPayRequest request, WalletSnapshot snapshot) async {
15 if (!request.hasContract) {
16 return const NoTokenRequested();
17 }
18
19 final contract = request.contractAddress!;
20 final detectedType = request.detection.detectedWalletType;
21
22 if (detectedType != null && isEVMCompatibleChain(detectedType)) {
23 return _resolveEvm(request, snapshot, contract);
24 }
25
26 final token = await _tokenLookup.findTokenByAddress(
27 walletType: detectedType ?? snapshot.type,
28 address: contract,
29 );
30
31 if (token == null) {
32 return TokenUnknown(contract);
33 }
34
35 return TokenResolved(
36 token: token,
37 amountOverride: request.paymentRequest.resolveTokenAmount(token),
38 );
39 }
40
41 Future<AnyPayResolution> _resolveEvm(
42 AnyPayRequest request,
43 WalletSnapshot snapshot,
44 String contract,
45 ) async {
46 final requestedChainId = AnyPayRouter.requestedEvmChainId(request, snapshot) ?? 1;
47
48 final lookupType = snapshot.supportedEvmChains[requestedChainId];
49 if (lookupType != null) {
50 final token =
51 await _tokenLookup.findTokenByAddress(walletType: lookupType, address: contract);
52 if (token != null) {
53 return TokenResolved(
54 token: token,
55 chainId: requestedChainId,
56 amountOverride: request.paymentRequest.resolveTokenAmount(token),
57 );
58 }
59 }
60
61 // The QRs from our old app versions omit the chainId on mainnet, so a contract the target
62 // network does not know may still belong to another EVM network.
63 if (request.chainBinding is ChainlessEvm) {
64 final reboundChainId = await _tokenLookup.findEvmChainIdForContract(
65 contract,
66 excludingChainId: requestedChainId,
67 );
68 final reboundType =
69 reboundChainId != null ? snapshot.supportedEvmChains[reboundChainId] : null;
70 if (reboundType != null) {
71 final token =
72 await _tokenLookup.findTokenByAddress(walletType: reboundType, address: contract);
73 if (token != null) {
74 return TokenResolved(
75 token: token,
76 chainId: reboundChainId,
77 amountOverride: request.paymentRequest.resolveTokenAmount(token),
78 );
79 }
80 }
81 }
82
83 return TokenUnknown(contract);
84 }
85 }
86
87 abstract class AnyPayTokenLookup {
88 Future<CryptoCurrency?> findTokenByAddress({
89 required WalletType walletType,
90 required String address,
91 });
92
93 Future<int?> findEvmChainIdForContract(String contractAddress, {int? excludingChainId});
94 }
95
96 class TokenUtilitiesLookup implements AnyPayTokenLookup {
97 const TokenUtilitiesLookup();
98
99 @override
100 Future<CryptoCurrency?> findTokenByAddress({
101 required WalletType walletType,
102 required String address,
103 }) =>
104 TokenUtilities.findTokenByAddress(walletType: walletType, address: address);
105
106 @override
107 Future<int?> findEvmChainIdForContract(String contractAddress, {int? excludingChainId}) =>
108 TokenUtilities.findEvmChainIdForContract(contractAddress, excludingChainId: excludingChainId);
109 }