Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-519-tor

This commit is contained in:
Matthew Fosse 2024-03-13 08:33:11 -07:00
commit 5ecce49f5f
20 changed files with 311 additions and 56 deletions

View file

@ -16,6 +16,7 @@ jobs:
env: env:
STORE_PASS: test@cake_wallet STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet KEY_PASS: test@cake_wallet
PR_NUMBER: ${{ github.event.number }}
steps: steps:
- name: is pr - name: is pr
@ -163,10 +164,7 @@ jobs:
- name: Rename app - name: Rename app
run: | run: |
hash=`sha512sum <<<"${{ env.BRANCH_NAME }}"` echo -e "id=com.cakewallet.test_${{ env.PR_NUMBER }}\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties
substring=${hash:0:15}
echo substring
echo -e "id=com.cakewallet.test_$(substring)\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties
- name: Build - name: Build
run: | run: |

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

View file

@ -216,7 +216,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
static const usdcEPoly = CryptoCurrency(title: 'USDC.E', tag: 'POLY', fullName: 'USD Coin (PoS)', raw: 88, name: 'usdcepoly', iconPath: 'assets/images/usdc_icon.png', decimals: 6); static const usdcEPoly = CryptoCurrency(title: 'USDC.E', tag: 'POLY', fullName: 'USD Coin (PoS)', raw: 88, name: 'usdcepoly', iconPath: 'assets/images/usdc_icon.png', decimals: 6);
static const kaspa = CryptoCurrency(title: 'KAS', fullName: 'Kaspa', raw: 89, name: 'kas', iconPath: 'assets/images/kaspa_icon.png', decimals: 8); static const kaspa = CryptoCurrency(title: 'KAS', fullName: 'Kaspa', raw: 89, name: 'kas', iconPath: 'assets/images/kaspa_icon.png', decimals: 8);
static const digibyte = CryptoCurrency(title: 'DGB', fullName: 'DigiByte', raw: 90, name: 'dgb', iconPath: 'assets/images/digibyte.png', decimals: 8); static const digibyte = CryptoCurrency(title: 'DGB', fullName: 'DigiByte', raw: 90, name: 'dgb', iconPath: 'assets/images/digibyte.png', decimals: 8);
static const usdtSol = CryptoCurrency(title: 'USDT', tag: 'SOL', fullName: 'USDT Tether', raw: 90, name: 'usdtsol', iconPath: 'assets/images/usdt_icon.png', decimals: 6); static const usdtSol = CryptoCurrency(title: 'USDT', tag: 'SOL', fullName: 'USDT Tether', raw: 91, name: 'usdtsol', iconPath: 'assets/images/usdt_icon.png', decimals: 6);
static final Map<int, CryptoCurrency> _rawCurrencyMap = static final Map<int, CryptoCurrency> _rawCurrencyMap =

View file

@ -183,13 +183,8 @@ abstract class MoneroWalletBase
// try to use the date instead: // try to use the date instead:
try { try {
_setHeightFromDate(); _setHeightFromDate();
} catch (e, s) { } catch (_) {
// we still couldn't get a valid sync height :/ // we still couldn't get a valid sync height :/
onError?.call(FlutterErrorDetails(
exception: e,
stack: s,
library: this.runtimeType.toString(),
));
} }
} }
} }
@ -287,7 +282,9 @@ abstract class MoneroWalletBase
pendingTransactionDescription = await transaction_history.createTransaction( pendingTransactionDescription = await transaction_history.createTransaction(
address: address!, address: address!,
amount: amount, amount: amount,
priorityRaw: _credentials.priority.serialize(), priorityRaw: _credentials.priority == MoneroTransactionPriority.automatic
? MoneroTransactionPriority.medium.serialize()
: _credentials.priority.serialize(),
accountIndex: walletAddresses.account!.id, accountIndex: walletAddresses.account!.id,
preferredInputs: inputs); preferredInputs: inputs);
} }

View file

@ -165,16 +165,6 @@ abstract class SolanaWalletBase
throw Exception("Solana Node connection failed"); throw Exception("Solana Node connection failed");
} }
try {
await Future.wait([
_updateBalance(),
_updateNativeSOLTransactions(),
_updateSPLTokenTransactions(),
]);
} catch (e) {
log(e.toString());
}
_setTransactionUpdateTimer(); _setTransactionUpdateTimer();
syncStatus = ConnectedSyncStatus(); syncStatus = ConnectedSyncStatus();

View file

@ -380,17 +380,19 @@ Future<void> setup({
fiatConvertationStore: getIt.get<FiatConversionStore>())); fiatConvertationStore: getIt.get<FiatConversionStore>()));
getIt.registerFactory(() => DashboardViewModel( getIt.registerFactory(() => DashboardViewModel(
balanceViewModel: getIt.get<BalanceViewModel>(), balanceViewModel: getIt.get<BalanceViewModel>(),
appStore: getIt.get<AppStore>(), appStore: getIt.get<AppStore>(),
tradesStore: getIt.get<TradesStore>(), tradesStore: getIt.get<TradesStore>(),
tradeFilterStore: getIt.get<TradeFilterStore>(), tradeFilterStore: getIt.get<TradeFilterStore>(),
transactionFilterStore: getIt.get<TransactionFilterStore>(), transactionFilterStore: getIt.get<TransactionFilterStore>(),
settingsStore: settingsStore, settingsStore: settingsStore,
yatStore: getIt.get<YatStore>(), yatStore: getIt.get<YatStore>(),
ordersStore: getIt.get<OrdersStore>(), ordersStore: getIt.get<OrdersStore>(),
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>(), anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>(),
keyService: getIt.get<KeyService>(), keyService: getIt.get<KeyService>(),
torViewModel: getIt.get<TorViewModel>())); torViewModel: getIt.get<TorViewModel>(),
sharedPreferences: getIt.get<SharedPreferences>(),
));
getIt.registerFactory<AuthService>( getIt.registerFactory<AuthService>(
() => AuthService( () => AuthService(

View file

@ -76,4 +76,5 @@ class PreferencesKey {
static const lastSeenAppVersion = 'last_seen_app_version'; static const lastSeenAppVersion = 'last_seen_app_version';
static const shouldShowMarketPlaceInDashboard = 'should_show_marketplace_in_dashboard'; static const shouldShowMarketPlaceInDashboard = 'should_show_marketplace_in_dashboard';
static const isNewInstall = 'is_new_install'; static const isNewInstall = 'is_new_install';
static const serviceStatusShaKey = 'service_status_sha_key';
} }

View file

@ -0,0 +1,41 @@
class ServiceStatus {
final String title;
final String description;
final String? image;
final String? status;
final DateTime date;
ServiceStatus(
{required this.title,
required this.description,
required this.date,
this.image,
this.status});
factory ServiceStatus.fromJson(Map<String, dynamic> json) => ServiceStatus(
title: json['title'] as String? ?? '',
description: json['description'] as String? ?? '',
date: DateTime.tryParse(json['date'] as String? ?? '') ?? DateTime.now(),
image: json['image'] as String?,
status: json['status'] as String?,
);
}
class ServicesResponse {
final List<ServiceStatus> servicesStatus;
final bool hasUpdates;
final String currentSha;
ServicesResponse(this.servicesStatus, this.hasUpdates, this.currentSha);
factory ServicesResponse.fromJson(
Map<String, dynamic> json, bool hasUpdates, String currentSha) {
return ServicesResponse(
(json['notices'] as List? ?? [])
.map((e) => ServiceStatus.fromJson(e as Map<String, dynamic>))
.toList(),
hasUpdates,
currentSha,
);
}
}

View file

@ -110,7 +110,7 @@ class CWSolana extends Solana {
@override @override
List<int>? getValidationLength(CryptoCurrency type) { List<int>? getValidationLength(CryptoCurrency type) {
if (type is SPLToken) { if (type is SPLToken) {
return [44]; return [32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44];
} }
return null; return null;

View file

@ -7,6 +7,7 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sideba
import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart'; import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart'; import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
import 'package:cake_wallet/src/widgets/gradient_background.dart'; import 'package:cake_wallet/src/widgets/gradient_background.dart';
import 'package:cake_wallet/src/widgets/services_updates_widget.dart';
import 'package:cake_wallet/src/widgets/vulnerable_seeds_popup.dart'; import 'package:cake_wallet/src/widgets/vulnerable_seeds_popup.dart';
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart'; import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/device_info.dart';
@ -102,6 +103,9 @@ class _DashboardPageView extends BasePage {
@override @override
Widget get endDrawer => MenuWidget(dashboardViewModel); Widget get endDrawer => MenuWidget(dashboardViewModel);
@override
Widget leading(BuildContext context) => ServicesUpdatesWidget(dashboardViewModel.getServicesStatus());
@override @override
Widget middle(BuildContext context) { Widget middle(BuildContext context) {
return SyncIndicator( return SyncIndicator(

View file

@ -179,7 +179,7 @@ class BaseAlertDialog extends StatelessWidget {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
if (headerText != null) headerTitle(context), if (headerText?.isNotEmpty ?? false) headerTitle(context),
Padding( Padding(
padding: EdgeInsets.fromLTRB(24, 20, 24, 0), padding: EdgeInsets.fromLTRB(24, 20, 24, 0),
child: title(context), child: title(context),

View file

@ -0,0 +1,71 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:cake_wallet/entities/service_status.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class ServiceStatusTile extends StatelessWidget {
final ServiceStatus status;
const ServiceStatusTile(this.status, {super.key});
@override
Widget build(BuildContext context) {
return ListTile(
contentPadding: const EdgeInsets.all(8),
title: Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: AutoSizeText(
"${status.title}${status.status != null ? " - ${status.status}" : ""}",
style: TextStyle(
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.w800,
height: 1,
),
maxLines: 1,
textAlign: TextAlign.start,
),
),
Text(
_getTimeString(status.date),
style: TextStyle(fontSize: 12),
),
],
),
),
leading: RotatedBox(
child: Icon(
Icons.info,
color: status.status == "resolved" ? Colors.green : Colors.red,
),
quarterTurns: 2,
),
subtitle: Row(
children: [
Expanded(child: Text(status.description)),
if (status.image != null)
SizedBox(
height: 50,
width: 50,
child: Image.network(status.image!),
),
],
),
);
}
String _getTimeString(DateTime date) {
int difference = DateTime.now().difference(date).inHours;
if (difference == 0) {
return "few minutes ago";
}
if (difference < 24) {
return DateFormat('h:mm a').format(date);
}
return DateFormat('d-MM-yyyy').format(date);
}
}

View file

@ -0,0 +1,120 @@
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/entities/service_status.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/service_status_tile.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';
class ServicesUpdatesWidget extends StatelessWidget {
final Future<ServicesResponse> servicesResponse;
const ServicesUpdatesWidget(this.servicesResponse, {super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: FutureBuilder<ServicesResponse>(
future: servicesResponse,
builder: (context, state) {
return InkWell(
onTap: state.hasData
? () {
// save currentSha when the user see the status
getIt
.get<SharedPreferences>()
.setString(PreferencesKey.serviceStatusShaKey, state.data!.currentSha);
showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(50),
topRight: Radius.circular(50),
),
),
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height / 2,
minHeight: MediaQuery.of(context).size.height / 4,
),
builder: (context) {
Widget body;
if (state.data!.servicesStatus.isEmpty) {
body = Center(
child: Text("Everything is up and running as expected"),
);
} else {
body = SingleChildScrollView(
child: Column(
children: state.data!.servicesStatus
.map((status) => ServiceStatusTile(status))
.toList()),
);
}
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 20),
child: Stack(
children: [
body,
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width / 8),
child: PrimaryImageButton(
onPressed: () {
try {
launchUrl(Uri.parse("https://status.cakewallet.com/"));
} catch (_) {}
},
image: Image.asset(
"assets/images/status_website_image.png",
color: Theme.of(context).brightness == Brightness.light
? Colors.white
: null,
),
text: "Status Website",
color: Theme.of(context)
.extension<WalletListTheme>()!
.createNewWalletButtonBackgroundColor,
textColor: Theme.of(context)
.extension<WalletListTheme>()!
.restoreWalletButtonTextColor,
),
),
)
],
),
);
},
);
}
: null,
child: Stack(
children: [
Image.asset(
"assets/images/notification_icon.png",
color: Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
),
if (state.hasData && state.data!.hasUpdates)
Container(
height: 7,
width: 7,
margin: EdgeInsetsDirectional.only(start: 8),
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
),
],
),
);
},
),
);
}
}

View file

@ -4,8 +4,10 @@ import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/core/key_service.dart'; import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart'; import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/balance_display_mode.dart'; import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/entities/provider_types.dart'; import 'package:cake_wallet/entities/provider_types.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/service_status.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart'; import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/monero/monero.dart'; import 'package:cake_wallet/monero/monero.dart';
@ -46,25 +48,29 @@ import 'package:flutter/services.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/entities/provider_types.dart'; import 'package:cake_wallet/entities/provider_types.dart';
import 'package:tor/tor.dart'; import 'package:tor/tor.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
part 'dashboard_view_model.g.dart'; part 'dashboard_view_model.g.dart';
class DashboardViewModel = DashboardViewModelBase with _$DashboardViewModel; class DashboardViewModel = DashboardViewModelBase with _$DashboardViewModel;
abstract class DashboardViewModelBase with Store { abstract class DashboardViewModelBase with Store {
DashboardViewModelBase( DashboardViewModelBase({
{required this.balanceViewModel, required this.balanceViewModel,
required this.appStore, required this.appStore,
required this.tradesStore, required this.tradesStore,
required this.tradeFilterStore, required this.tradeFilterStore,
required this.transactionFilterStore, required this.transactionFilterStore,
required this.settingsStore, required this.settingsStore,
required this.yatStore, required this.yatStore,
required this.ordersStore, required this.ordersStore,
required this.anonpayTransactionsStore, required this.anonpayTransactionsStore,
required this.keyService, required this.keyService,
required this.torViewModel}) required this.torViewModel,
: hasSellAction = false, required this.sharedPreferences,
required this.keyService,
}) : hasSellAction = false,
hasBuyAction = false, hasBuyAction = false,
hasExchangeAction = false, hasExchangeAction = false,
isShowFirstYatIntroduction = false, isShowFirstYatIntroduction = false,
@ -288,6 +294,7 @@ abstract class DashboardViewModelBase with Store {
[WalletType.bitcoin, WalletType.litecoin, WalletType.bitcoinCash].contains(wallet.type); [WalletType.bitcoin, WalletType.litecoin, WalletType.bitcoinCash].contains(wallet.type);
final KeyService keyService; final KeyService keyService;
final SharedPreferences sharedPreferences;
BalanceViewModel balanceViewModel; BalanceViewModel balanceViewModel;
@ -514,4 +521,26 @@ abstract class DashboardViewModelBase with Store {
return affectedWallets; return affectedWallets;
} }
Future<ServicesResponse> getServicesStatus() async {
try {
final res = await http.get(Uri.parse("https://service-api.cakewallet.com/v1/active-notices"));
if (res.statusCode < 200 || res.statusCode >= 300) {
throw res.body;
}
final oldSha = sharedPreferences.getString(PreferencesKey.serviceStatusShaKey);
final hash = await Cryptography.instance.sha256().hash(utf8.encode(res.body));
final currentSha = bytesToHex(hash.bytes);
final hasUpdates = oldSha != currentSha;
return ServicesResponse.fromJson(
json.decode(res.body) as Map<String, dynamic>, hasUpdates, currentSha);
} catch (_) {
return ServicesResponse([], false, '');
}
}
} }

View file

@ -427,9 +427,10 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
) { ) {
if (walletType == WalletType.ethereum || if (walletType == WalletType.ethereum ||
walletType == WalletType.polygon || walletType == WalletType.polygon ||
walletType == WalletType.solana ||
walletType == WalletType.haven) { walletType == WalletType.haven) {
if (error.contains('gas required exceeds allowance') || if (error.contains('gas required exceeds allowance') ||
error.contains('insufficient funds for')) { error.contains('insufficient funds')) {
return S.current.do_not_have_enough_gas_asset(currency.toString()); return S.current.do_not_have_enough_gas_asset(currency.toString());
} }

View file

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
. ./config.sh . ./config.sh
MONERO_BRANCH=release-v0.18.2.2-android MONERO_BRANCH=release-v0.18.2.2-android_tx_priority_fix
MONERO_SRC_DIR=${WORKDIR}/monero MONERO_SRC_DIR=${WORKDIR}/monero
git clone https://github.com/cake-tech/monero.git ${MONERO_SRC_DIR} --branch ${MONERO_BRANCH} git clone https://github.com/cake-tech/monero.git ${MONERO_SRC_DIR} --branch ${MONERO_BRANCH}

View file

@ -4,7 +4,7 @@
MONERO_URL="https://github.com/cake-tech/monero.git" MONERO_URL="https://github.com/cake-tech/monero.git"
MONERO_DIR_PATH="${EXTERNAL_IOS_SOURCE_DIR}/monero" MONERO_DIR_PATH="${EXTERNAL_IOS_SOURCE_DIR}/monero"
MONERO_VERSION=release-v0.18.2.2 MONERO_VERSION=release-v0.18.2.2_tx_priority_fix
BUILD_TYPE=release BUILD_TYPE=release
PREFIX=${EXTERNAL_IOS_DIR} PREFIX=${EXTERNAL_IOS_DIR}
DEST_LIB_DIR=${EXTERNAL_IOS_LIB_DIR}/monero DEST_LIB_DIR=${EXTERNAL_IOS_LIB_DIR}/monero

View file

@ -8,9 +8,10 @@ SODIUM_URL="https://github.com/jedisct1/libsodium.git"
echo "============================ SODIUM ============================" echo "============================ SODIUM ============================"
echo "Cloning SODIUM from - $SODIUM_URL" echo "Cloning SODIUM from - $SODIUM_URL"
git clone $SODIUM_URL $SODIUM_PATH --branch stable git clone $SODIUM_URL $SODIUM_PATH
cd $SODIUM_PATH cd $SODIUM_PATH
./dist-build/ios.sh git checkout 443617d7507498f7477703f0b51cb596d4539262
./dist-build/apple-xcframework.sh
mv ${SODIUM_PATH}/libsodium-ios/include/* $EXTERNAL_IOS_INCLUDE_DIR mv ${SODIUM_PATH}/libsodium-apple/ios/include/* $EXTERNAL_IOS_INCLUDE_DIR
mv ${SODIUM_PATH}/libsodium-ios/lib/* $EXTERNAL_IOS_LIB_DIR mv ${SODIUM_PATH}/libsodium-apple/ios/lib/* $EXTERNAL_IOS_LIB_DIR

View file

@ -4,7 +4,7 @@
MONERO_URL="https://github.com/cake-tech/monero.git" MONERO_URL="https://github.com/cake-tech/monero.git"
MONERO_DIR_PATH="${EXTERNAL_MACOS_SOURCE_DIR}/monero" MONERO_DIR_PATH="${EXTERNAL_MACOS_SOURCE_DIR}/monero"
MONERO_VERSION=release-v0.18.2.2 MONERO_VERSION=release-v0.18.2.2_tx_priority_fix
BUILD_TYPE=release BUILD_TYPE=release
PREFIX=${EXTERNAL_MACOS_DIR} PREFIX=${EXTERNAL_MACOS_DIR}
DEST_LIB_DIR=${EXTERNAL_MACOS_LIB_DIR}/monero DEST_LIB_DIR=${EXTERNAL_MACOS_LIB_DIR}/monero