Merge branch 'cake-tech:dev' into dev

This commit is contained in:
BSN ∞/21M
2026-06-11 07:45:15 +02:00
committed by GitHub
11 changed files with 106 additions and 51 deletions
+10 -2
View File
@@ -116,10 +116,18 @@ jobs:
./scripts/prepare_moneroc.sh
mkdir -p scripts/monero_c/release
pushd scripts/monero_c/release
mkdir -p $(git describe --tags)
pushd $(git describe --tags)
TAG=$(git describe --tags)
mkdir -p "$TAG"
pushd "$TAG"
wget https://github.com/MrCyjaneK/monero_c/releases/download/v0.18.4.6-RC2/release-bundle.zip
unzip release-bundle.zip
# RC2's bundle puts everything under an inner v0.18.4.6-*/ dir, strip it
shopt -s nullglob
for inner in v0.18.4.6-*/; do
mv "$inner"* .
rmdir "$inner"
done
shopt -u nullglob
rm release-bundle.zip
popd
popd
+22 -4
View File
@@ -176,14 +176,23 @@ class PolygonURI extends PaymentURI {
}
class SolanaURI extends PaymentURI {
SolanaURI({required super.amount, required super.address});
SolanaURI({required super.amount, required super.address, this.contractAddress});
final String? contractAddress;
@override
String toString() {
var base = 'solana:$address';
final params = <String>[];
if (amount.isNotEmpty) {
base += '?amount=${amount.replaceAll(',', '.')}';
params.add('amount=${amount.replaceAll(',', '.')}');
}
if (contractAddress != null && contractAddress!.isNotEmpty) {
params.add('spl-token=$contractAddress');
}
if (params.isNotEmpty) {
base += '?${params.join('&')}';
}
return base;
@@ -191,14 +200,23 @@ class SolanaURI extends PaymentURI {
}
class TronURI extends PaymentURI {
TronURI({required super.amount, required super.address});
TronURI({required super.amount, required super.address, this.contractAddress});
final String? contractAddress;
@override
String toString() {
var base = 'tron:$address';
final params = <String>[];
if (amount.isNotEmpty) {
base += '?amount=${amount.replaceAll(',', '.')}';
params.add('amount=${amount.replaceAll(',', '.')}');
}
if (contractAddress != null && contractAddress!.isNotEmpty) {
params.add('token=$contractAddress');
}
if (params.isNotEmpty) {
base += '?${params.join('&')}';
}
return base;
@@ -28,6 +28,9 @@ class SolanaTransactionInfo extends TransactionInfo {
String? _fiatAmount;
@override
String get txHash => id.replaceFirst(RegExp(r'_(outgoing|incoming)$'), '');
@override
DateTime get date => blockTime;
+8
View File
@@ -228,6 +228,14 @@ class _NewSendPageState extends State<NewSendPage> {
_addressControllers[0].text = widget.initialPaymentRequest!.address;
_amountControllers[0].text = widget.initialPaymentRequest!.amount;
_memoControllers[0].text = widget.initialPaymentRequest!.note;
final contractAddress = widget.initialPaymentRequest!.contractAddress;
if (contractAddress != null && contractAddress.isNotEmpty) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
widget.sendViewModel.fetchTokenForContractAddress(contractAddress);
}
});
}
}
/// if the current wallet doesn't match the one in the qr code
+1 -1
View File
@@ -363,7 +363,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
arguments: [availableWalletTypes.first, hardwareWalletType]),
isReconnect: false,
),
getIt.get<LedgerViewModel>(),
getIt.get<HardwareWalletViewModel>(param1: hardwareWalletType),
),
);
}
+9 -9
View File
@@ -264,6 +264,10 @@ class BuySellPage extends BasePage {
final cryptoAmountController = cryptoCurrencyKey.currentState!.amountController;
final cryptoAddressController = cryptoCurrencyKey.currentState!.addressController;
cryptoAddressController.addListener(() {
buySellViewModel.changeCryptoCurrencyAddress(cryptoAddressController.text);
});
_onCurrencyChange(buySellViewModel.cryptoCurrency, buySellViewModel, cryptoCurrencyKey);
_onCurrencyChange(buySellViewModel.fiatCurrency, buySellViewModel, fiatCurrencyKey);
@@ -313,10 +317,6 @@ class BuySellPage extends BasePage {
}
});
cryptoAddressController.addListener(() {
buySellViewModel.changeCryptoCurrencyAddress(cryptoAddressController.text);
});
_cryptoAddressFocus.addListener(() async {
if (!_cryptoAddressFocus.hasFocus && cryptoAddressController.text.isNotEmpty) {
final domain = cryptoAddressController.text;
@@ -325,7 +325,7 @@ class BuySellPage extends BasePage {
}
});
reaction((_) => buySellViewModel.wallet.walletAddresses.addressForExchange, (String address) {
reaction((_) => buySellViewModel.wallet.walletAddresses.addressForBuy, (String address) {
if (buySellViewModel.cryptoCurrency == CryptoCurrency.xmr) {
cryptoCurrencyKey.currentState!.changeAddress(address: address);
}
@@ -359,7 +359,7 @@ class BuySellPage extends BasePage {
key.currentState!.changeAddress(
address:
isCurrentTypeWallet ? buySellViewModel.wallet.walletAddresses.addressForExchange : '');
isCurrentTypeWallet ? buySellViewModel.wallet.walletAddresses.addressForBuy : '');
key.currentState!.changeAmount(amount: '');
}
@@ -371,9 +371,9 @@ class BuySellPage extends BasePage {
if (isCurrentTypeWallet) {
key.currentState!.changeWalletName(buySellViewModel.wallet.name);
key.currentState!.addressController.text =
buySellViewModel.wallet.walletAddresses.addressForExchange;
buySellViewModel.wallet.walletAddresses.addressForBuy;
} else if (key.currentState!.addressController.text ==
buySellViewModel.wallet.walletAddresses.addressForExchange) {
buySellViewModel.wallet.walletAddresses.addressForBuy) {
key.currentState!.changeWalletName('');
key.currentState!.addressController.text = '';
}
@@ -429,7 +429,7 @@ class BuySellPage extends BasePage {
initialCurrency: buySellViewModel.cryptoCurrency,
initialWalletName: '',
initialAddress: buySellViewModel.cryptoCurrency == buySellViewModel.wallet.currency
? buySellViewModel.wallet.walletAddresses.addressForExchange
? buySellViewModel.wallet.walletAddresses.addressForBuy
: buySellViewModel.cryptoCurrencyAddress,
initialIsAmountEditable: true,
isAmountEstimated: true,
+10
View File
@@ -60,6 +60,16 @@ class PaymentRequest {
address = paymentUri.address;
amount = paymentUri.amount;
contractAddress = paymentUri.contractAddress;
} else if (scheme == "tron") {
final token = uri.queryParameters['token'];
if (token != null && token.isNotEmpty) {
contractAddress = token;
}
} else if (scheme == "solana") {
final splToken = uri.queryParameters['spl-token'];
if (splToken != null && splToken.isNotEmpty) {
contractAddress = splToken;
}
}
}
+8 -27
View File
@@ -144,7 +144,7 @@ class TokenUtilities {
return result;
}
/// Finds a token by address across wallets depending on [walletType]
/// Finds a token by address for the given [walletType].
/// - EVM chains: match by contractAddress
/// - Solana: match by mintAddress
/// - Tron: match by contractAddress
@@ -152,34 +152,15 @@ class TokenUtilities {
required WalletType walletType,
required String address,
}) async {
if(address.isEmpty) return null;
if (address.isEmpty) return null;
final lower = address.toLowerCase();
switch (walletType) {
case WalletType.ethereum:
case WalletType.polygon:
case WalletType.base:
case WalletType.arbitrum:
case WalletType.bsc:
final tokens = await loadAllUniqueEvmTokens();
for (final t in tokens) {
if (t.contractAddress.toLowerCase() == lower) return t;
}
return null;
case WalletType.solana:
final solTokens = await loadAllUniqueSolTokens();
for (final t in solTokens) {
if (t.mintAddress.toLowerCase() == lower) return t;
}
return null;
case WalletType.tron:
final tronTokens = await loadAllUniqueTronTokens();
for (final t in tronTokens) {
if (t.contractAddress.toLowerCase() == lower) return t;
}
return null;
default:
return null;
final tokens = await getAvailableTokensForNetwork(walletType);
for (final t in tokens) {
if (t is Erc20Token && t.contractAddress.toLowerCase() == lower) return t;
if (t is SPLToken && t.mintAddress.toLowerCase() == lower) return t;
if (t is TronToken && t.contractAddress.toLowerCase() == lower) return t;
}
return null;
}
static Future<Box<Erc20Token>> _openEvmTokensBoxFor(WalletInfo walletInfo) async {
+17 -8
View File
@@ -7,6 +7,7 @@ import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/bottom_sheet/bottom_sheet_message_display_widget.dart';
import 'package:cake_wallet/evm/evm.dart';
import 'package:cake_wallet/utils/debounce.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:mobx/mobx.dart';
@@ -31,12 +32,14 @@ abstract class NFTViewModelBase with Store {
if (wallet != null) return wallet.chainId;
return null;
}, (_) => getNFTAssetByWallet());
}, (_) => _fetchDebounce.run(() => getNFTAssetByWallet()));
}
}
final AppStore appStore;
bool _nftErrorPopupShown = false;
final BottomSheetService bottomSheetService;
final Debounce _fetchDebounce = Debounce(const Duration(milliseconds: 500));
@observable
bool isLoading;
@@ -100,6 +103,8 @@ abstract class NFTViewModelBase with Store {
final decodedResponse = jsonDecode(response.body);
_nftErrorPopupShown = false;
if (wallet.type == WalletType.solana) {
final results = await Future.wait(
(decodedResponse as List<dynamic>).map(
@@ -115,7 +120,8 @@ abstract class NFTViewModelBase with Store {
solanaNftAssetModels.addAll(results);
} else {
final result = WalletNFTsResponseModel.fromJson(decodedResponse as Map<String, dynamic>).result ?? [];
final result =
WalletNFTsResponseModel.fromJson(decodedResponse as Map<String, dynamic>).result ?? [];
nftAssetByWalletModels.clear();
@@ -123,12 +129,15 @@ abstract class NFTViewModelBase with Store {
}
} catch (e) {
log(e.toString());
bottomSheetService.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(
message: S.current.moralis_nft_error,
),
);
if (!_nftErrorPopupShown) {
_nftErrorPopupShown = true;
bottomSheetService.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(
message: S.current.moralis_nft_error,
),
);
}
} finally {
isLoading = false;
}
@@ -1071,6 +1071,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
}
if (depositCurrency == CryptoCurrency.btcln &&
wallet.type == WalletType.bitcoin &&
depositAddress == wallet.walletAddresses.addressForExchange) {
final invoice = await bitcoin!.getLightningInvoice(wallet, BigInt.zero);
if (invoice != null) {
@@ -1079,6 +1080,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
}
if (receiveCurrency == CryptoCurrency.btcln &&
wallet.type == WalletType.bitcoin &&
receiveAddress == wallet.walletAddresses.addressForExchange) {
final invoice = await bitcoin!.getLightningInvoice(wallet, BigInt.zero);
if (invoice != null) {
@@ -34,6 +34,8 @@ import 'package:cw_core/currency.dart';
import 'package:cw_core/currency_for_wallet_type.dart';
import 'package:cw_core/erc20_token.dart';
import 'package:cw_core/payment_uris.dart';
import 'package:cw_core/spl_token.dart';
import 'package:cw_core/tron_token.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:mobx/mobx.dart';
@@ -202,6 +204,20 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
amount: _amount,
contractAddress: (tokenCurrency as Erc20Token).contractAddress);
}
if (tokenCurrency is TronToken && wallet.type == WalletType.tron) {
return TronURI(
amount: _amount,
address: wallet.walletAddresses.address,
contractAddress: (tokenCurrency as TronToken).contractAddress,
);
}
if (tokenCurrency is SPLToken && wallet.type == WalletType.solana) {
return SolanaURI(
amount: _amount,
address: wallet.walletAddresses.address,
contractAddress: (tokenCurrency as SPLToken).mintAddress,
);
}
if (isLightning && _lnPaymentRequest != null) return _lnPaymentRequest!;
return wallet.walletAddresses.getPaymentUri(_amount);
}