Merge remote-tracking branch 'origin/main' into electrum-sp-refactors

This commit is contained in:
Rafael Saes 2024-11-27 06:50:56 -03:00
commit 3ee697b4c1
29 changed files with 353 additions and 177 deletions

View file

@ -1,6 +1,3 @@
-
uri: electrum.cakewallet.com:50002
useSSL: true
-
uri: btc-electrum.cakewallet.com:50002
useSSL: true

View file

@ -2,6 +2,7 @@
uri: xmr-node.cakewallet.com:18081
is_default: true
trusted: true
useSSL: true
-
uri: cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081
is_default: false

View file

@ -203,9 +203,30 @@ class Node extends HiveObject with Keyable {
headers: {'Content-Type': 'application/json'},
body: json.encode(body),
);
client.close();
if ((
response.body.contains("400 Bad Request") // Some other generic error
|| response.body.contains("plain HTTP request was sent to HTTPS port") // Cloudflare
|| response.headers["location"] != null // Generic reverse proxy
|| response.body.contains("301 Moved Permanently") // Poorly configured generic reverse proxy
) && !(useSSL??false)
) {
final oldUseSSL = useSSL;
useSSL = true;
try {
final ret = await requestMoneroNode();
if (ret == true) {
await save();
return ret;
}
useSSL = oldUseSSL;
} catch (e) {
useSSL = oldUseSSL;
}
}
final resBody = json.decode(response.body) as Map<String, dynamic>;
return !(resBody['result']['offline'] as bool);
} catch (_) {

View file

@ -2,14 +2,14 @@ group 'com.cakewallet.cw_haven'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.7.10'
ext.kotlin_version = '2.0.21'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.0'
classpath 'com.android.tools.build:gradle:8.7.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
@ -25,8 +25,20 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 28
compileSdkVersion 33
if (project.android.hasProperty("namespace")) {
namespace 'com.cakewallet.cw_haven'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}

View file

@ -17,7 +17,7 @@ String getTxKey(String txId) {
final status = monero.Wallet_status(wptr!);
if (status != 0) {
final error = monero.Wallet_errorString(wptr!);
return txId+"_"+error;
return "";
}
return txKey;
}
@ -92,11 +92,18 @@ Future<PendingTransactionDescription> createTransactionSync(
final amt = amount == null ? 0 : monero.Wallet_amountFromString(amount);
final waddr = wptr!.address;
// force reconnection in case the os killed the connection?
// fixes failed to get block height error.
Isolate.run(() async {
monero.Wallet_synchronized(Pointer.fromAddress(waddr));
});
final address_ = address.toNativeUtf8();
final paymentId_ = paymentId.toNativeUtf8();
final preferredInputs_ = preferredInputs.join(monero.defaultSeparatorStr).toNativeUtf8();
final waddr = wptr!.address;
final addraddr = address_.address;
final paymentIdAddr = paymentId_.address;
final preferredInputsAddr = preferredInputs_.address;
@ -357,16 +364,7 @@ class Transaction {
confirmations = monero.TransactionInfo_confirmations(txInfo),
fee = monero.TransactionInfo_fee(txInfo),
description = monero.TransactionInfo_description(txInfo),
key = getTxKey(txInfo);
static String getTxKey(monero.TransactionInfo txInfo) {
final txKey = monero.Wallet_getTxKey(wptr!, txid: monero.TransactionInfo_hash(txInfo));
final status = monero.Wallet_status(wptr!);
if (status != 0) {
return "";
}
return txKey;
}
key = getTxKey(monero.TransactionInfo_hash(txInfo));
Transaction.dummy({
required this.displayLabel,

View file

@ -150,14 +150,15 @@ final storeMutex = Mutex();
int lastStorePointer = 0;
int lastStoreHeight = 0;
void storeSync() async {
void storeSync({bool force = false}) async {
final addr = wptr!.address;
final synchronized = await Isolate.run(() {
return monero.Wallet_synchronized(Pointer.fromAddress(addr));
});
if (lastStorePointer == wptr!.address &&
lastStoreHeight + 5000 > monero.Wallet_blockChainHeight(wptr!) &&
!synchronized) {
!synchronized &&
!force) {
return;
}
lastStorePointer = wptr!.address;

View file

@ -286,8 +286,18 @@ Future<void> loadWallet(
/// 0: Software Wallet
/// 1: Ledger
/// 2: Trezor
final deviceType = monero.WalletManager_queryWalletDevice(wmPtr,
keysFileName: "$path.keys", password: password, kdfRounds: 1);
late final deviceType;
if (Platform.isAndroid || Platform.isIOS) {
deviceType = monero.WalletManager_queryWalletDevice(
wmPtr,
keysFileName: "$path.keys",
password: password,
kdfRounds: 1,
);
} else {
deviceType = 0;
}
if (deviceType == 1) {
final dummyWPtr = wptr ??

View file

@ -6,6 +6,7 @@ import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/amount_converter.dart';
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_monero/api/wallet.dart';
class DoubleSpendException implements Exception {
DoubleSpendException();
@ -53,6 +54,7 @@ class PendingMoneroTransaction with PendingTransaction {
rethrow;
}
storeSync(force: true);
}
@override

View file

@ -25,7 +25,20 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 30
compileSdkVersion 33
if (project.android.hasProperty("namespace")) {
namespace 'com.cakewallet.cw_shared_external'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'

View file

@ -252,7 +252,11 @@ class OnRamperBuyProvider extends BuyProvider {
case 'POL':
return 'POLYGON';
default:
return CryptoCurrency.fromString(tag).fullName ?? tag;
try {
return CryptoCurrency.fromString(tag).fullName!;
} catch (_) {
return tag;
}
}
}

View file

@ -260,10 +260,34 @@ Future<void> defaultSettingsMigration(
updateBtcElectrumNodeToUseSSL(nodes, sharedPreferences);
break;
case 43:
_updateCakeXmrNode(nodes);
await _updateCakeXmrNode(nodes);
_deselectExchangeProvider(sharedPreferences, "THORChain");
_deselectExchangeProvider(sharedPreferences, "SimpleSwap");
break;
case 44:
await _updateCakeXmrNode(nodes);
await _changeDefaultNode(
nodes: nodes,
sharedPreferences: sharedPreferences,
type: WalletType.bitcoin,
newDefaultUri: newCakeWalletBitcoinUri,
currentNodePreferenceKey: PreferencesKey.currentBitcoinElectrumSererIdKey,
useSSL: true,
oldUri: ['cakewallet.com'],
);
_changeDefaultNode(
nodes: nodes,
sharedPreferences: sharedPreferences,
type: WalletType.tron,
newDefaultUri: tronDefaultNodeUri,
currentNodePreferenceKey: PreferencesKey.currentTronNodeIdKey,
useSSL: true,
oldUri: [
'tron-rpc.publicnode.com:443',
'api.trongrid.io',
],
);
break;
default:
break;
@ -279,17 +303,54 @@ Future<void> defaultSettingsMigration(
await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version);
}
void _updateCakeXmrNode(Box<Node> nodes) {
/// generic function for changing any wallet default node
/// instead of making a new function for each change
Future<void> _changeDefaultNode({
required Box<Node> nodes,
required SharedPreferences sharedPreferences,
required WalletType type,
required String newDefaultUri,
required String currentNodePreferenceKey,
required bool useSSL,
required List<String> oldUri, // leave empty if you want to force replace the node regardless of the user's current node
}) async {
final currentNodeId = sharedPreferences.getInt(currentNodePreferenceKey);
final currentNode = nodes.values.firstWhere((node) => node.key == currentNodeId);
final shouldReplace = oldUri.any((e) => currentNode.uriRaw.contains(e));
if (shouldReplace) {
var newNodeId =
nodes.values.firstWhereOrNull((element) => element.uriRaw == newDefaultUri)?.key;
// new node doesn't exist, then add it
if (newNodeId == null) {
final newNode = Node(
uri: newDefaultUri,
type: type,
useSSL: useSSL,
);
await nodes.add(newNode);
newNodeId = newNode.key;
}
await sharedPreferences.setInt(currentNodePreferenceKey, newNodeId as int);
}
}
Future<void> _updateCakeXmrNode(Box<Node> nodes) async {
final node = nodes.values.firstWhereOrNull((element) => element.uriRaw == newCakeWalletMoneroUri);
if (node != null && !node.trusted) {
if (node != null) {
node.trusted = true;
node.save();
node.useSSL = true;
await node.save();
}
}
void updateBtcElectrumNodeToUseSSL(Box<Node> nodes, SharedPreferences sharedPreferences) {
final btcElectrumNode = nodes.values.firstWhereOrNull((element) => element.uriRaw == newCakeWalletBitcoinUri);
final btcElectrumNode =
nodes.values.firstWhereOrNull((element) => element.uriRaw == newCakeWalletBitcoinUri);
if (btcElectrumNode != null) {
btcElectrumNode.useSSL = true;
@ -538,7 +599,6 @@ Node? getBitcoinCashDefaultElectrumServer({required Box<Node> nodes}) {
}
Node getMoneroDefaultNode({required Box<Node> nodes}) {
final timeZone = DateTime.now().timeZoneOffset.inHours;
var nodeUri = newCakeWalletMoneroUri;
try {
@ -858,7 +918,8 @@ Future<void> changeDefaultMoneroNode(
}
});
final newCakeWalletNode = Node(uri: newCakeWalletMoneroUri, type: WalletType.monero, trusted: true);
final newCakeWalletNode =
Node(uri: newCakeWalletMoneroUri, type: WalletType.monero, trusted: true);
await nodeSource.add(newCakeWalletNode);
@ -897,7 +958,7 @@ Future<void> updateBtcNanoWalletInfos(Box<WalletInfo> walletsInfoSource) async {
Future<void> changeDefaultNanoNode(
Box<Node> nodeSource, SharedPreferences sharedPreferences) async {
const oldNanoNodeUriPattern = 'rpc.nano.to';
final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
final currentNanoNode = nodeSource.values.firstWhere((node) => node.key == currentNanoNodeId);
final newCakeWalletNode = Node(
@ -909,7 +970,8 @@ Future<void> changeDefaultNanoNode(
await nodeSource.add(newCakeWalletNode);
if (currentNanoNode.uri.toString().contains(oldNanoNodeUriPattern)) {
await sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, newCakeWalletNode.key as int);
await sharedPreferences.setInt(
PreferencesKey.currentNanoNodeIdKey, newCakeWalletNode.key as int);
}
}
@ -924,7 +986,7 @@ Future<void> changeDefaultBitcoinNode(
currentBitcoinNode.uri.toString().contains(cakeWalletBitcoinNodeUriPattern);
final newCakeWalletBitcoinNode =
Node(uri: newCakeWalletBitcoinUri, type: WalletType.bitcoin, useSSL: false);
Node(uri: newCakeWalletBitcoinUri, type: WalletType.bitcoin, useSSL: true);
if (!nodeSource.values.any((element) => element.uriRaw == newCakeWalletBitcoinUri)) {
await nodeSource.add(newCakeWalletBitcoinNode);

View file

@ -1,7 +1,5 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter/material.dart';
@ -68,7 +66,7 @@ class MainActions {
static MainActions tradeAction = MainActions._(
name: (context) => '${S.of(context).buy} / ${S.of(context).sell}',
name: (context) => '${S.of(context).buy}/${S.of(context).sell}',
image: 'assets/images/buy_sell.png',
isEnabled: (viewModel) => viewModel.isEnabledTradeAction,
canShow: (viewModel) => viewModel.hasTradeAction,

View file

@ -26,23 +26,80 @@ class AddressResolver {
final SettingsStore settingsStore;
static const unstoppableDomains = [
'crypto',
'zil',
'x',
'wallet',
'bitcoin',
'888',
'nft',
'dao',
'blockchain',
'polygon',
'klever',
'hi',
'kresus',
'anime',
'manga',
'binanceus',
'xmr',
"888",
"altimist",
"anime",
"austin",
"bald",
"benji",
"bet",
"binanceus",
"bitcoin",
"bitget",
"blockchain",
"ca",
"chomp",
"clay",
"co",
"com",
"crypto",
"dao",
"dfz",
"digital",
"dream",
"eth",
"ethermail",
"farms",
"fun",
"go",
"group",
"hi",
"host",
"info",
"io",
"klever",
"kresus",
"kryptic",
"lfg",
"life",
"live",
"ltd",
"manga",
"metropolis",
"moon",
"mumu",
"net",
"nft",
"online",
"org",
"pog",
"polygon",
"press",
"pro",
"propykeys",
"pudgy",
"pw",
"raiin",
"secret",
"site",
"smobler",
"space",
"stepn",
"store",
"tball",
"tech",
"ubu",
"uno",
"unstoppable",
"wallet",
"website",
"wifi",
"witg",
"wrkx",
"x",
"xmr",
"xyz",
"zil",
];
static String? extractAddressByType({required String raw, required CryptoCurrency type}) {

View file

@ -203,7 +203,7 @@ Future<void> initializeAppConfigs() async {
transactionDescriptions: transactionDescriptions,
secureStorage: secureStorage,
anonpayInvoiceInfo: anonpayInvoiceInfo,
initialMigrationVersion: 43,
initialMigrationVersion: 44,
);
}

View file

@ -63,6 +63,8 @@ void startCurrentWalletChangeReaction(
startWalletSyncStatusChangeReaction(wallet, fiatConversionStore);
startCheckConnectionReaction(wallet, settingsStore);
await Future.delayed(Duration.zero);
if (wallet.type == WalletType.monero ||
wallet.type == WalletType.wownero ||
wallet.type == WalletType.bitcoin ||

View file

@ -291,7 +291,8 @@ class _DashboardPageView extends BasePage {
children: MainActions.all
.where((element) => element.canShow?.call(dashboardViewModel) ?? true)
.map(
(action) => Semantics(
(action) => Expanded(
child: Semantics(
button: true,
enabled: (action.isEnabled?.call(dashboardViewModel) ?? true),
child: ActionButton(
@ -319,6 +320,7 @@ class _DashboardPageView extends BasePage {
.labelTextColor,
),
),
),
)
.toList(),
),

View file

@ -10,25 +10,17 @@ import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter_svg/flutter_svg.dart';
class CakeFeaturesPage extends StatelessWidget {
CakeFeaturesPage({required this.dashboardViewModel, required this.cakeFeaturesViewModel});
final DashboardViewModel dashboardViewModel;
final CakeFeaturesViewModel cakeFeaturesViewModel;
final _scrollController = ScrollController();
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: RawScrollbar(
thumbColor: Colors.white.withOpacity(0.15),
radius: Radius.circular(20),
thumbVisibility: true,
thickness: 2,
controller: _scrollController,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Column(
@ -45,7 +37,6 @@ class CakeFeaturesPage extends StatelessWidget {
),
Expanded(
child: ListView(
controller: _scrollController,
children: <Widget>[
SizedBox(height: 20),
DashBoardRoundedCardWidget(
@ -96,7 +87,6 @@ class CakeFeaturesPage extends StatelessWidget {
],
),
),
),
);
}

View file

@ -8,7 +8,7 @@ class SyncIndicatorIcon extends StatelessWidget {
{this.boolMode = true,
this.isSynced = false,
this.value = waiting,
this.size = 4.0});
this.size = 6.0});
final bool boolMode;
final bool isSynced;

View file

@ -191,6 +191,7 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
height = wownero!.getHeightByDate(date: date);
}
}
if (mounted) {
setState(() {
dateController.text = DateFormat('yyyy-MM-dd').format(date);
restoreHeightController.text = '$height';
@ -198,6 +199,7 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
});
}
}
}
void _changeHeight(int height) {
_height = height;

View file

@ -92,15 +92,17 @@ class _ServicesUpdatesWidgetState extends State<ServicesUpdatesWidget> {
);
}
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 20),
child: Stack(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Column(
children: [
body,
Expanded(child: body),
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width / 8),
horizontal: MediaQuery.of(context).size.width / 8,
vertical: 20,
),
child: PrimaryImageButton(
onPressed: () {
try {

View file

@ -50,8 +50,8 @@ abstract class AppStoreBase with Store {
getIt.get<Web3WalletService>().create();
await getIt.get<Web3WalletService>().init();
}
await getIt.get<SharedPreferences>().setString(PreferencesKey.currentWalletName, wallet.name);
await getIt
getIt.get<SharedPreferences>().setString(PreferencesKey.currentWalletName, wallet.name);
getIt
.get<SharedPreferences>()
.setInt(PreferencesKey.currentWalletType, serializeToInt(wallet.type));
}

View file

@ -204,7 +204,11 @@ abstract class CakePayCardsListViewModelBase with Store {
}
@action
void setSelectedCountry(Country country) => settingsStore.selectedCakePayCountry = country;
void setSelectedCountry(Country country) {
// just so it triggers the reaction even when selecting the default country
settingsStore.selectedCakePayCountry = null;
settingsStore.selectedCakePayCountry = country;
}
@action
void togglePrepaidCards() => displayPrepaidCards = !displayPrepaidCards;

View file

@ -159,7 +159,7 @@ abstract class TransactionDetailsViewModelBase with Store {
case WalletType.monero:
return 'https://monero.com/tx/${txId}';
case WalletType.bitcoin:
return 'https://mempool.space/${wallet.isTestnet ? "testnet/" : ""}tx/${txId}';
return 'https://mempool.cakewallet.com/${wallet.isTestnet ? "testnet/" : ""}tx/${txId}';
case WalletType.litecoin:
return 'https://blockchair.com/litecoin/transaction/${txId}';
case WalletType.bitcoinCash:

View file

@ -26,7 +26,7 @@ dependencies:
share_plus: ^10.0.0
# date_range_picker: ^1.0.6
#https://api.flutter.dev/flutter/material/showDateRangePicker.html
dio: ^4.0.6
dio: ^5.7.0
hive: ^2.2.3
hive_flutter: ^1.1.0
local_auth_android: ^1.0.46

View file

@ -921,7 +921,7 @@
"wallet_seed_legacy": "Graine de portefeuille hérité",
"wallet_store_monero_wallet": "Portefeuille (Wallet) Monero",
"walletConnect": "WalletConnect",
"wallets": "Portefeuilles (Wallets)",
"wallets": "Portefeuilles",
"warning": "Avertissement",
"welcome": "Bienvenue sur",
"welcome_to_cakepay": "Bienvenue sur Cake Pay !",

View file

@ -7,9 +7,9 @@ fi
cd ../..
set -x
universal_sed "0,/version:/{s/version:.*/version: ${APP_ANDROID_VERSION}+${APP_ANDROID_BUILD_NUMBER}/}" ./pubspec.yaml
universal_sed "0,/version:/{s/__APP_PACKAGE__/${APP_ANDROID_PACKAGE}/}" ./android/app/src/main/AndroidManifest.xml
universal_sed "0,/__APP_SCHEME__/s/__APP_SCHEME__/${APP_ANDROID_SCHEME}/" ./android/app/src/main/AndroidManifest.xml
universal_sed "0,/version:/{s/__versionCode__/${APP_ANDROID_BUILD_NUMBER}/}" ./android/app/src/main/AndroidManifest.xml
universal_sed "0,/version:/{s/__versionName__/${APP_ANDROID_VERSION}/}" ./android/app/src/main/AndroidManifest.xml
universal_sed "1,/version:/ {s/version:.*/version: ${APP_ANDROID_VERSION}+${APP_ANDROID_BUILD_NUMBER}/;}" ./pubspec.yaml
universal_sed "1,/version:/ {s/__APP_PACKAGE__/${APP_ANDROID_PACKAGE}/;}" ./android/app/src/main/AndroidManifest.xml
universal_sed "1,/__APP_SCHEME__/ {s/__APP_SCHEME__/${APP_ANDROID_SCHEME}/;}" ./android/app/src/main/AndroidManifest.xml
universal_sed "1,/version:/ {s/__versionCode__/${APP_ANDROID_BUILD_NUMBER}/;}" ./android/app/src/main/AndroidManifest.xml
universal_sed "1,/version:/ {s/__versionName__/${APP_ANDROID_VERSION}/;}" ./android/app/src/main/AndroidManifest.xml
cd scripts/android

View file

@ -43,7 +43,6 @@ case $APP_IOS_TYPE in
CONFIG_ARGS="--haven"
;;
esac
CONFIG_ARGS="--monero --ethereum --polygon --nano --solana --tron --wownero"
cp -rf pubspec_description.yaml pubspec.yaml
flutter pub get

View file

@ -16,13 +16,13 @@ if [ -n "$1" ]; then
fi
MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.8.0"
MONERO_COM_BUILD_NUMBER=36
MONERO_COM_VERSION="1.8.1"
MONERO_COM_BUILD_NUMBER=37
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="1.14.0"
CAKEWALLET_BUILD_NUMBER=95
CAKEWALLET_VERSION="1.14.1"
CAKEWALLET_BUILD_NUMBER=96
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then

View file

@ -13,7 +13,6 @@ universal_sed() {
local file=$2
if [[ "$SED_TYPE" == "GNU" ]]; then
pwd
sed -i "$expression" "$file"
else
sed -i '' "$expression" "$file"