mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
fix: anypay (#3507)
* fix android CI * fix: handle the parser seeing chainless QRs in the old flow as belonging to the current wallet, causing the error jack reported * fix: handle network switch when anypay is interrupted mid flow and currency is changed
This commit is contained in:
@@ -64,6 +64,7 @@ import "package:cw_core/amount/amount_sanitizer.dart";
|
||||
import "package:cw_core/amount/money.dart";
|
||||
import "package:cw_core/crypto_currency.dart";
|
||||
import "package:cw_core/currency_for_wallet_type.dart";
|
||||
import "package:cw_core/erc20_token.dart";
|
||||
import "package:cw_core/lnurl.dart";
|
||||
import "package:cw_core/payment_uris.dart";
|
||||
import "package:cw_core/transaction_priority.dart";
|
||||
@@ -247,35 +248,17 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
|
||||
if (widget.initialPaymentRequest != null) {
|
||||
if (_isInitialRequestTypeSameAsCurrentWallet()) {
|
||||
_addressControllers[0].text = widget.initialPaymentRequest!.address;
|
||||
// _memoControllers[0].text = widget.initialPaymentRequest!.note;
|
||||
_applyNote(widget.initialPaymentRequest!.note, 0);
|
||||
final contractAddress = widget.initialPaymentRequest!.contractAddress;
|
||||
if (contractAddress != null && contractAddress.isNotEmpty) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
final token = await TokenUtilities.findTokenByAddress(
|
||||
walletType: widget.sendViewModel.wallet.type,
|
||||
address: contractAddress,
|
||||
);
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (token == null) {
|
||||
_showUnsupportedTokenAlert();
|
||||
return;
|
||||
}
|
||||
await widget.sendViewModel.fetchTokenForContractAddress(contractAddress);
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
_amountControllers[0].text =
|
||||
widget.initialPaymentRequest!.resolveTokenAmount(token) ?? "";
|
||||
await _applyPaymentSelectingCurrency(widget.initialPaymentRequest!, null);
|
||||
});
|
||||
} else {
|
||||
_addressControllers[0].text = widget.initialPaymentRequest!.address;
|
||||
_applyNote(widget.initialPaymentRequest!.note, 0);
|
||||
_amountControllers[0].text = widget.initialPaymentRequest!.amount;
|
||||
}
|
||||
} else {
|
||||
@@ -1049,8 +1032,9 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
|
||||
Future<void> _handleManualNetworkSelection(ChainInfo target) async {
|
||||
final address = _addressControllers[_selectedOutput].text.trim();
|
||||
final amount = _amountControllers[_selectedOutput].text;
|
||||
final note = _memoControllers[_selectedOutput].text;
|
||||
final isTokenSelected = widget.sendViewModel.selectedCryptoCurrency is Erc20Token;
|
||||
final amount = isTokenSelected ? "" : _amountControllers[_selectedOutput].text;
|
||||
final paymentRequest = PaymentRequest(address, amount, note, "", null);
|
||||
await _handleEvmNetworkFlow(target, paymentRequest);
|
||||
}
|
||||
@@ -1153,7 +1137,7 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
if (isCrossChain) {
|
||||
await _handleEvmNetworkFlow(targetChain, paymentRequest);
|
||||
} else if (widget.sendViewModel.isEVMWallet) {
|
||||
_applyPaymentRequest(paymentRequest);
|
||||
await _applyPaymentSelectingCurrency(paymentRequest, null);
|
||||
} else {
|
||||
await _showEvmNetworkPicker(paymentRequest, result.walletType);
|
||||
}
|
||||
@@ -1328,8 +1312,12 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
String? amountOverride;
|
||||
final contract = paymentRequest.contractAddress;
|
||||
if (contract != null && contract.isNotEmpty) {
|
||||
final walletType = widget.sendViewModel.wallet.type;
|
||||
final lookupType = evm != null && isEVMCompatibleChain(walletType)
|
||||
? (evm!.getWalletTypeByChainId(_currentEvmChainIdOrMainnet()) ?? walletType)
|
||||
: walletType;
|
||||
final token = await TokenUtilities.findTokenByAddress(
|
||||
walletType: widget.sendViewModel.wallet.type,
|
||||
walletType: lookupType,
|
||||
address: contract,
|
||||
);
|
||||
if (!mounted) {
|
||||
@@ -1337,13 +1325,21 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
}
|
||||
|
||||
if (token == null) {
|
||||
final rerouted = await _rerouteChainlessContractPayment(paymentRequest);
|
||||
if (rerouted || !mounted) {
|
||||
return;
|
||||
}
|
||||
_showUnsupportedTokenAlert();
|
||||
return;
|
||||
}
|
||||
await widget.sendViewModel.fetchTokenForContractAddress(contract);
|
||||
await widget.sendViewModel.fetchTokenForContractAddress(contract, walletType: lookupType);
|
||||
amountOverride = paymentRequest.resolveTokenAmount(token);
|
||||
} else if (fallbackCurrency != null) {
|
||||
widget.sendViewModel.setSelectedCryptoCurrency(fallbackCurrency.title);
|
||||
if (paymentRequest.amount.isEmpty) {
|
||||
widget.sendViewModel.outputs[_selectedOutput].setCryptoAmount("");
|
||||
_amountControllers[_selectedOutput].clear();
|
||||
}
|
||||
}
|
||||
if (!mounted) {
|
||||
return;
|
||||
@@ -1351,6 +1347,44 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
_applyPaymentRequest(paymentRequest, amountOverride: amountOverride);
|
||||
}
|
||||
|
||||
Future<bool> _rerouteChainlessContractPayment(PaymentRequest paymentRequest) async {
|
||||
if (evm == null || paymentRequest.chainId != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (paymentRequest.scheme.toLowerCase() != "ethereum") {
|
||||
return false;
|
||||
}
|
||||
|
||||
final contract = paymentRequest.contractAddress;
|
||||
if (contract == null || contract.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final currentChainId = isEVMCompatibleChain(widget.sendViewModel.wallet.type)
|
||||
? _currentEvmChainIdOrMainnet()
|
||||
: null;
|
||||
|
||||
// QRs from old app versions omit the chainId on mainnet, so a contract the current
|
||||
// network does not know may still belong to another EVM network
|
||||
final chainId = await TokenUtilities.findEvmChainIdForContract(
|
||||
contract,
|
||||
excludingChainId: currentChainId,
|
||||
);
|
||||
if (chainId == null || !mounted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final targetChain = evm!.getChainInfoByChainId(chainId);
|
||||
if (targetChain == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printV("chainless contract payment rerouted to chainId $chainId");
|
||||
await _handleEvmNetworkFlow(targetChain, paymentRequest);
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> _completeWalletSwitch(
|
||||
WalletInfo wallet,
|
||||
PaymentFlowResult result,
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:cw_core/currency_for_wallet_type.dart';
|
||||
import 'package:cw_core/erc20_token.dart';
|
||||
import 'package:cw_core/spl_token.dart';
|
||||
import 'package:cw_core/tron_token.dart';
|
||||
import "package:cw_core/utils/print_verbose.dart";
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
@@ -163,6 +164,37 @@ class TokenUtilities {
|
||||
return null;
|
||||
}
|
||||
|
||||
static Future<int?> findEvmChainIdForContract(
|
||||
String contractAddress, {
|
||||
int? excludingChainId,
|
||||
}) async {
|
||||
if (evm == null || contractAddress.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
for (final chain in evm!.getAllChains()) {
|
||||
if (chain.chainId == excludingChainId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final walletType = evm!.getWalletTypeByChainId(chain.chainId);
|
||||
if (walletType == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final token = await findTokenByAddress(walletType: walletType, address: contractAddress);
|
||||
if (token != null) {
|
||||
return chain.chainId;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
printV("findEvmChainIdForContract failed: $e");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Future<Box<Erc20Token>> _openEvmTokensBoxFor(WalletInfo walletInfo) async {
|
||||
final walletKey = walletInfo.name.replaceAll(' ', '_');
|
||||
final boxName = _getErc20TokensBoxName(walletKey, walletInfo.type);
|
||||
|
||||
@@ -126,9 +126,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
super(appStore: _appStore) {
|
||||
outputs.add(Output(wallet, _appStore, _fiatConversationStore, _outputCryptoCurrencyHandler));
|
||||
|
||||
unspentCoinsListViewModel
|
||||
.initialSetup();
|
||||
// .then((_) => unspentCoinsListViewModel.resetUnspentCoinsInfoSelections());
|
||||
unspentCoinsListViewModel.initialSetup();
|
||||
// .then((_) => unspentCoinsListViewModel.resetUnspentCoinsInfoSelections());
|
||||
|
||||
reaction((_) {
|
||||
if (isEVMCompatibleChain(wallet.type)) {
|
||||
@@ -1719,9 +1718,10 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
String? payjoinUri;
|
||||
|
||||
@action
|
||||
Future<void> fetchTokenForContractAddress(String contractAddress) async {
|
||||
Future<void> fetchTokenForContractAddress(String contractAddress,
|
||||
{WalletType? walletType}) async {
|
||||
final token = await TokenUtilities.findTokenByAddress(
|
||||
walletType: wallet.type,
|
||||
walletType: walletType ?? wallet.type,
|
||||
address: contractAddress,
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user