mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
Merge branch 'cake-tech:dev' into dev
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -363,7 +363,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||
arguments: [availableWalletTypes.first, hardwareWalletType]),
|
||||
isReconnect: false,
|
||||
),
|
||||
getIt.get<LedgerViewModel>(),
|
||||
getIt.get<HardwareWalletViewModel>(param1: hardwareWalletType),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user