v4.10.0 & v1.7.0 (#1113)

* New versions

* update the new version text after macos [skip ci]

* add cake-wallet headers

* add nano/banano to getAddressFromStringPattern

* Revert "Exolix integration (#1080)"

This reverts commit 9eb6867ab9.

* fix: Bug in conditions check and clean up of repeated code in switch cases (#1117)

* update build numbers [skip ci]

---------

Co-authored-by: fosse <matt.cfosse@gmail.com>
Co-authored-by: Adegoke David <64401859+Blazebrain@users.noreply.github.com>
This commit is contained in:
Omar Hatem 2023-10-09 18:18:59 +03:00 committed by GitHub
parent 5a20d342ad
commit e5408a388e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 146 additions and 554 deletions

View file

@ -128,7 +128,6 @@ jobs:
echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
echo "const robinhoodCIdApiSecret = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -1,3 +1,3 @@
Fix 2FA code issue
Support getting Addresses from ENS and Mastodon
Bug fixes
Minor enhancements

View file

@ -1,4 +1,5 @@
Ethereum enhancements and bug fixes
Fix 2FA code issue
Add Nano wallet
Add WalletConnect to connect your ETH wallet with your favorite dApp
Support getting Addresses from ENS and Mastodon
Bug fixes
Minor enhancements

View file

@ -13,6 +13,11 @@ class NanoClient {
static const String DEFAULT_REPRESENTATIVE =
"nano_38713x95zyjsqzx6nm1dsom1jmm668owkeb9913ax6nfgj15az3nu8xkx579";
static const Map<String, String> CAKE_HEADERS = {
"Content-Type": "application/json",
"nano-app": "cake-wallet"
};
Node? _node;
Node? _powNode;
@ -37,7 +42,7 @@ class NanoClient {
Future<NanoBalance> getBalance(String address) async {
final response = await http.post(
_node!.uri,
headers: {"Content-Type": "application/json"},
headers: CAKE_HEADERS,
body: jsonEncode(
{
"action": "account_balance",
@ -57,7 +62,7 @@ class NanoClient {
try {
final response = await http.post(
_node!.uri,
headers: {"Content-Type": "application/json"},
headers: CAKE_HEADERS,
body: jsonEncode(
{
"action": "account_info",
@ -123,7 +128,7 @@ class NanoClient {
Future<String> requestWork(String hash) async {
final response = await http.post(
_powNode!.uri,
headers: {'Content-type': 'application/json'},
headers: CAKE_HEADERS,
body: json.encode(
{
"action": "work_generate",
@ -157,7 +162,6 @@ class NanoClient {
}
Future<String> processBlock(Map<String, String> block, String subtype) async {
final headers = {"Content-Type": "application/json"};
final processBody = jsonEncode({
"action": "process",
"json_block": "true",
@ -167,7 +171,7 @@ class NanoClient {
final processResponse = await http.post(
_node!.uri,
headers: headers,
headers: CAKE_HEADERS,
body: processBody,
);
@ -260,10 +264,6 @@ class NanoClient {
}) async {
bool openBlock = false;
final headers = {
"Content-Type": "application/json",
};
// first check if the account is open:
// get the account info (we need the frontier and representative):
AccountInfoResponse? infoData = await getAccountInfo(destinationAddress);
@ -335,7 +335,7 @@ class NanoClient {
});
final processResponse = await http.post(
_node!.uri,
headers: headers,
headers: CAKE_HEADERS,
body: processBody,
);
@ -351,7 +351,7 @@ class NanoClient {
required String privateKey,
}) async {
final receivableResponse = await http.post(_node!.uri,
headers: {"Content-Type": "application/json"},
headers: CAKE_HEADERS,
body: jsonEncode({
"action": "receivable",
"account": destinationAddress,
@ -401,7 +401,7 @@ class NanoClient {
Future<List<NanoTransactionModel>> fetchTransactions(String address) async {
try {
final response = await http.post(_node!.uri,
headers: {"Content-Type": "application/json"},
headers: CAKE_HEADERS,
body: jsonEncode({
"action": "account_history",
"account": address,

View file

@ -267,6 +267,10 @@ class AddressValidator extends TextValidator {
'|([^0-9a-zA-Z]|^)ltc[a-zA-Z0-9]{26,45}([^0-9a-zA-Z]|\$)';
case CryptoCurrency.eth:
return '0x[0-9a-zA-Z]{42}';
case CryptoCurrency.nano:
return 'nano_[0-9a-zA-Z]{60}';
case CryptoCurrency.banano:
return 'ban_[0-9a-zA-Z]{60}';
default:
return null;
}

View file

@ -1,6 +1,7 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:cake_wallet/utils/device_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
@ -308,7 +309,7 @@ class BackupService {
if (currentPinLength != null)
await _sharedPreferences.setInt(PreferencesKey.currentPinLength, currentPinLength);
if (currentTheme != null)
if (currentTheme != null && DeviceInfo.instance.isMobile)
await _sharedPreferences.setInt(PreferencesKey.currentTheme, currentTheme);
if (exchangeStatus != null)

View file

@ -417,10 +417,6 @@ Future<void> setup({
}
if (appStore.wallet != null) {
authStore.allowed();
if (appStore.wallet!.type == WalletType.ethereum) {
getIt.get<Web3WalletService>().init();
}
return;
}
@ -441,10 +437,6 @@ Future<void> setup({
} else {
if (appStore.wallet != null) {
authStore.allowed();
if (appStore.wallet!.type == WalletType.ethereum) {
getIt.get<Web3WalletService>().init();
}
return;
}

View file

@ -6,6 +6,7 @@ class Cake2FAPresetsOptions extends EnumerableItem<int> with Serializable<int> {
static const narrow = Cake2FAPresetsOptions(title: 'Narrow', raw: 0);
static const normal = Cake2FAPresetsOptions(title: 'Normal', raw: 1);
static const aggressive = Cake2FAPresetsOptions(title: 'Aggressive', raw: 2);
static const none = Cake2FAPresetsOptions(title: 'None', raw: 3);
static Cake2FAPresetsOptions deserialize({required int raw}) {
switch (raw) {
@ -15,6 +16,8 @@ class Cake2FAPresetsOptions extends EnumerableItem<int> with Serializable<int> {
return Cake2FAPresetsOptions.normal;
case 2:
return Cake2FAPresetsOptions.aggressive;
case 3:
return Cake2FAPresetsOptions.none;
default:
throw Exception(
'Incorrect Cake 2FA Preset $raw for Cake2FAPresetOptions deserialize',

View file

@ -24,10 +24,7 @@ class ExchangeProviderDescription extends EnumerableItem<int> with Serializable<
static const trocador =
ExchangeProviderDescription(title: 'Trocador', raw: 5, image: 'assets/images/trocador.png');
static const exolix =
ExchangeProviderDescription(title: 'Exolix', raw: 6, image: 'assets/images/exolix.png');
static const all = ExchangeProviderDescription(title: 'All trades', raw: 7, image: '');
static const all = ExchangeProviderDescription(title: 'All trades', raw: 6, image: '');
static ExchangeProviderDescription deserialize({required int raw}) {
switch (raw) {
@ -44,8 +41,6 @@ class ExchangeProviderDescription extends EnumerableItem<int> with Serializable<
case 5:
return trocador;
case 6:
return exolix;
case 7:
return all;
default:
throw Exception('Unexpected token: $raw for ExchangeProviderDescription deserialize');

View file

@ -1,294 +0,0 @@
import 'dart:convert';
import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
import 'package:http/http.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/exchange/exchange_pair.dart';
import 'package:cake_wallet/exchange/exchange_provider.dart';
import 'package:cake_wallet/exchange/limits.dart';
import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/exchange/exolix/exolix_request.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
class ExolixExchangeProvider extends ExchangeProvider {
ExolixExchangeProvider() : super(pairList: _supportedPairs());
static final apiKey = secrets.exolixApiKey;
static const apiBaseUrl = 'exolix.com';
static const transactionsPath = '/api/v2/transactions';
static const ratePath = '/api/v2/rate';
static const List<CryptoCurrency> _notSupported = [
CryptoCurrency.usdt,
CryptoCurrency.xhv,
CryptoCurrency.btt,
CryptoCurrency.firo,
CryptoCurrency.zaddr,
CryptoCurrency.xvg,
CryptoCurrency.kmd,
CryptoCurrency.paxg,
CryptoCurrency.rune,
CryptoCurrency.scrt,
CryptoCurrency.btcln,
CryptoCurrency.cro,
CryptoCurrency.ftm,
CryptoCurrency.frax,
CryptoCurrency.gusd,
CryptoCurrency.gtc,
CryptoCurrency.weth,
];
static List<ExchangePair> _supportedPairs() {
final supportedCurrencies =
CryptoCurrency.all.where((element) => !_notSupported.contains(element)).toList();
return supportedCurrencies
.map((i) => supportedCurrencies.map((k) => ExchangePair(from: i, to: k, reverse: true)))
.expand((i) => i)
.toList();
}
@override
String get title => 'Exolix';
@override
bool get isAvailable => true;
@override
bool get isEnabled => true;
@override
bool get supportsFixedRate => true;
@override
ExchangeProviderDescription get description => ExchangeProviderDescription.exolix;
@override
Future<bool> checkIsAvailable() async => true;
static String getRateType(bool isFixedRate) => isFixedRate ? 'fixed' : 'float';
@override
Future<Limits> fetchLimits(
{required CryptoCurrency from,
required CryptoCurrency to,
required bool isFixedRateMode}) async {
final params = <String, String>{
'rateType': getRateType(isFixedRateMode),
'amount': '1',
};
if (isFixedRateMode) {
params['coinFrom'] = _normalizeCurrency(to);
params['coinTo'] = _normalizeCurrency(from);
params['networkFrom'] = _networkFor(to);
params['networkTo'] = _networkFor(from);
} else {
params['coinFrom'] = _normalizeCurrency(from);
params['coinTo'] = _normalizeCurrency(to);
params['networkFrom'] = _networkFor(from);
params['networkTo'] = _networkFor(to);
}
final uri = Uri.https(apiBaseUrl, ratePath, params);
final response = await get(uri);
if (response.statusCode != 200) {
throw Exception('Unexpected http status: ${response.statusCode}');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
return Limits(min: responseJSON['minAmount'] as double?);
}
@override
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
final _request = request as ExolixRequest;
final headers = {'Content-Type': 'application/json'};
final body = <String, dynamic>{
'coinFrom': _normalizeCurrency(_request.from),
'coinTo': _normalizeCurrency(_request.to),
'networkFrom': _networkFor(_request.from),
'networkTo': _networkFor(_request.to),
'withdrawalAddress': _request.address,
'refundAddress': _request.refundAddress,
'rateType': getRateType(isFixedRateMode),
'apiToken': apiKey,
};
if (isFixedRateMode) {
body['withdrawalAmount'] = _request.toAmount;
} else {
body['amount'] = _request.fromAmount;
}
final uri = Uri.https(apiBaseUrl, transactionsPath);
final response = await post(uri, headers: headers, body: json.encode(body));
if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final errors = responseJSON['errors'] as Map<String, String>;
final errorMessage = errors.values.join(', ');
throw Exception(errorMessage);
}
if (response.statusCode != 200 && response.statusCode != 201) {
throw Exception('Unexpected http status: ${response.statusCode}');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final id = responseJSON['id'] as String;
final inputAddress = responseJSON['depositAddress'] as String;
final refundAddress = responseJSON['refundAddress'] as String?;
final extraId = responseJSON['depositExtraId'] as String?;
final payoutAddress = responseJSON['withdrawalAddress'] as String;
final amount = responseJSON['amount'].toString();
return Trade(
id: id,
from: _request.from,
to: _request.to,
provider: description,
inputAddress: inputAddress,
refundAddress: refundAddress,
extraId: extraId,
createdAt: DateTime.now(),
amount: amount,
state: TradeState.created,
payoutAddress: payoutAddress);
}
@override
Future<Trade> findTradeById({required String id}) async {
final findTradeByIdPath = transactionsPath + '/$id';
final uri = Uri.https(apiBaseUrl, findTradeByIdPath);
final response = await get(uri);
if (response.statusCode == 404) {
throw TradeNotFoundException(id, provider: description);
}
if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final errors = responseJSON['errors'] as Map<String, String>;
final errorMessage = errors.values.join(', ');
throw TradeNotFoundException(id, provider: description, description: errorMessage);
}
if (response.statusCode != 200) {
throw Exception('Unexpected http status: ${response.statusCode}');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final coinFrom = responseJSON['coinFrom']['coinCode'] as String;
final from = CryptoCurrency.fromString(coinFrom);
final coinTo = responseJSON['coinTo']['coinCode'] as String;
final to = CryptoCurrency.fromString(coinTo);
final inputAddress = responseJSON['depositAddress'] as String;
final amount = responseJSON['amount'].toString();
final status = responseJSON['status'] as String;
final state = TradeState.deserialize(raw: _prepareStatus(status));
final extraId = responseJSON['depositExtraId'] as String?;
final outputTransaction = responseJSON['hashOut']['hash'] as String?;
final payoutAddress = responseJSON['withdrawalAddress'] as String;
return Trade(
id: id,
from: from,
to: to,
provider: description,
inputAddress: inputAddress,
amount: amount,
state: state,
extraId: extraId,
outputTransaction: outputTransaction,
payoutAddress: payoutAddress);
}
@override
Future<double> fetchRate(
{required CryptoCurrency from,
required CryptoCurrency to,
required double amount,
required bool isFixedRateMode,
required bool isReceiveAmount}) async {
try {
if (amount == 0) {
return 0.0;
}
final params = <String, String>{
'coinFrom': _normalizeCurrency(from),
'coinTo': _normalizeCurrency(to),
'networkFrom': _networkFor(from),
'networkTo': _networkFor(to),
'rateType': getRateType(isFixedRateMode),
};
if (isReceiveAmount) {
params['withdrawalAmount'] = amount.toString();
} else {
params['amount'] = amount.toString();
}
final uri = Uri.https(apiBaseUrl, ratePath, params);
final response = await get(uri);
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
if (response.statusCode != 200) {
final message = responseJSON['message'] as String?;
throw Exception(message);
}
final rate = responseJSON['rate'] as double;
return rate;
} catch (e) {
print(e.toString());
return 0.0;
}
}
String _prepareStatus(String status) {
switch (status) {
case 'deleted':
case 'error':
return 'overdue';
default:
return status;
}
}
String _networkFor(CryptoCurrency currency) {
switch (currency) {
case CryptoCurrency.arb:
return 'ARBITRUM';
default:
return currency.tag != null ? _normalizeTag(currency.tag!) : currency.title;
}
}
String _normalizeCurrency(CryptoCurrency currency) {
switch (currency) {
case CryptoCurrency.nano:
return 'XNO';
case CryptoCurrency.bttc:
return 'BTT';
case CryptoCurrency.zec:
return 'ZEC';
default:
return currency.title;
}
}
String _normalizeTag(String tag) {
switch (tag) {
case 'POLY':
return 'Polygon';
default:
return tag;
}
}
}

View file

@ -1,20 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/exchange/trade_request.dart';
class ExolixRequest extends TradeRequest {
ExolixRequest(
{required this.from,
required this.to,
required this.address,
required this.fromAmount,
required this.toAmount,
required this.refundAddress});
CryptoCurrency from;
CryptoCurrency to;
String address;
String fromAmount;
String toAmount;
String refundAddress;
}

View file

@ -35,15 +35,6 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
static const completed = TradeState(raw: 'completed', title: 'Completed');
static const settling = TradeState(raw: 'settling', title: 'Settlement in progress');
static const settled = TradeState(raw: 'settled', title: 'Settlement completed');
static const wait = TradeState(raw: 'wait', title: 'Waiting');
static const overdue = TradeState(raw: 'overdue', title: 'Overdue');
static const refund = TradeState(raw: 'refund', title: 'Refund');
static const refunded = TradeState(raw: 'refunded', title: 'Refunded');
static const confirmation = TradeState(raw: 'confirmation', title: 'Confirmation');
static const confirmed = TradeState(raw: 'confirmed', title: 'Confirmed');
static const exchanging = TradeState(raw: 'exchanging', title: 'Exchanging');
static const sending = TradeState(raw: 'sending', title: 'Sending');
static const success = TradeState(raw: 'success', title: 'Success');
static TradeState deserialize({required String raw}) {
switch (raw) {
case 'pending':
@ -86,24 +77,6 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
return failed;
case 'completed':
return completed;
case 'wait':
return wait;
case 'overdue':
return overdue;
case 'refund':
return refund;
case 'refunded':
return refunded;
case 'confirmation':
return confirmation;
case 'confirmed':
return confirmed;
case 'exchanging':
return exchanging;
case 'sending':
return sending;
case 'success':
return success;
default:
throw Exception('Unexpected token: $raw in TradeState deserialize');
}

View file

@ -178,6 +178,11 @@ class CWNano extends Nano {
BigInt getTransactionAmountRaw(TransactionInfo transactionInfo) {
return (transactionInfo as NanoTransactionInfo).amountRaw;
}
@override
String getRepresentative(Object wallet) {
return (wallet as NanoWallet).representative;
}
}
class CWNanoUtil extends NanoUtil {
@ -308,14 +313,19 @@ class CWNanoUtil extends NanoUtil {
/// @param raw 100000000000000000000000000000
/// @return Decimal value 1.000000000000000000000000000000
///
@override
Decimal getRawAsDecimal(String? raw, BigInt? rawPerCur) {
Decimal _getRawAsDecimal(String? raw, BigInt? rawPerCur) {
rawPerCur ??= rawPerNano;
final Decimal amount = Decimal.parse(raw.toString());
final Decimal result = (amount / Decimal.parse(rawPerCur.toString())).toDecimal();
return result;
}
@override
String getRawAsDecimalString(String? raw, BigInt? rawPerCur) {
final Decimal result = _getRawAsDecimal(raw, rawPerCur);
return result.toString();
}
@override
String truncateDecimal(Decimal input, {int digits = maxDecimalDigits}) {
Decimal bigger = input.shift(digits);
@ -332,7 +342,7 @@ class CWNanoUtil extends NanoUtil {
@override
String getRawAsUsableString(String? raw, BigInt rawPerCur) {
final String res =
truncateDecimal(getRawAsDecimal(raw, rawPerCur), digits: maxDecimalDigits + 9);
truncateDecimal(_getRawAsDecimal(raw, rawPerCur), digits: maxDecimalDigits + 9);
if (raw == null || raw == "0" || raw == "00000000000000000000000000000000") {
return "0";
@ -361,7 +371,7 @@ class CWNanoUtil extends NanoUtil {
@override
String getRawAccuracy(String? raw, BigInt rawPerCur) {
final String rawString = getRawAsUsableString(raw, rawPerCur);
final String rawDecimalString = getRawAsDecimal(raw, rawPerCur).toString();
final String rawDecimalString = _getRawAsDecimal(raw, rawPerCur).toString();
if (raw == null || raw.isEmpty || raw == "0") {
return "";

View file

@ -94,9 +94,6 @@ class TradeRow extends StatelessWidget {
borderRadius: BorderRadius.circular(50),
child: Image.asset('assets/images/trocador.png', width: 36, height: 36));
break;
case ExchangeProviderDescription.exolix:
image = Image.asset('assets/images/exolix.png', width: 36, height: 36);
break;
default:
image = null;
}

View file

@ -6,7 +6,6 @@ import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_nano/nano_wallet.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
@ -18,7 +17,7 @@ class NanoChangeRepPage extends BasePage {
NanoChangeRepPage(WalletBase wallet)
: _wallet = wallet,
_addressController = TextEditingController() {
_addressController.text = (wallet as NanoWallet).representative;
_addressController.text = nano!.getRepresentative(wallet);
}
final TextEditingController _addressController;

View file

@ -85,7 +85,7 @@ class ConnectionSyncPage extends BasePage {
);
},
),
if (dashboardViewModel.wallet.type == WalletType.ethereum) ...[
if (dashboardViewModel.wallet.type == WalletType.ethereum && DeviceInfo.instance.isMobile) ...[
WalletConnectTile(
onTap: () async {
Navigator.of(context).push(

View file

@ -1,5 +1,8 @@
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_core/balance.dart';
import 'package:cw_core/wallet_base.dart';
@ -40,5 +43,9 @@ abstract class AppStoreBase with Store {
this.wallet?.close();
this.wallet = wallet;
this.wallet!.setExceptionHandler(ExceptionHandler.onError);
if (wallet.type == WalletType.ethereum) {
getIt.get<Web3WalletService>().init();
}
}
}

View file

@ -13,8 +13,7 @@ abstract class TradeFilterStoreBase with Store {
displaySideShift = true,
displayMorphToken = true,
displaySimpleSwap = true,
displayTrocador = true,
displayExolix = true;
displayTrocador = true;
@observable
bool displayXMRTO;
@ -34,11 +33,8 @@ abstract class TradeFilterStoreBase with Store {
@observable
bool displayTrocador;
@observable
bool displayExolix;
@computed
bool get displayAllTrades => displayChangeNow && displaySideShift && displaySimpleSwap && displayTrocador && displayExolix;
bool get displayAllTrades => displayChangeNow && displaySideShift && displaySimpleSwap && displayTrocador;
@action
void toggleDisplayExchange(ExchangeProviderDescription provider) {
@ -60,10 +56,7 @@ abstract class TradeFilterStoreBase with Store {
break;
case ExchangeProviderDescription.trocador:
displayTrocador = !displayTrocador;
break;
case ExchangeProviderDescription.exolix:
displayExolix = !displayExolix;
break;
break;
case ExchangeProviderDescription.all:
if (displayAllTrades) {
displayChangeNow = false;
@ -72,7 +65,6 @@ abstract class TradeFilterStoreBase with Store {
displayMorphToken = false;
displaySimpleSwap = false;
displayTrocador = false;
displayExolix = false;
} else {
displayChangeNow = true;
displaySideShift = true;
@ -80,7 +72,6 @@ abstract class TradeFilterStoreBase with Store {
displayMorphToken = true;
displaySimpleSwap = true;
displayTrocador = true;
displayExolix = true;
}
break;
}
@ -107,8 +98,7 @@ abstract class TradeFilterStoreBase with Store {
||(displaySimpleSwap &&
item.trade.provider ==
ExchangeProviderDescription.simpleSwap)
||(displayTrocador && item.trade.provider == ExchangeProviderDescription.trocador)
||(displayExolix && item.trade.provider == ExchangeProviderDescription.exolix))
||(displayTrocador && item.trade.provider == ExchangeProviderDescription.trocador))
.toList()
: _trades;
}

View file

@ -98,11 +98,6 @@ abstract class DashboardViewModelBase with Store {
caption: ExchangeProviderDescription.trocador.title,
onChanged: () => tradeFilterStore
.toggleDisplayExchange(ExchangeProviderDescription.trocador)),
FilterItem(
value: () => tradeFilterStore.displayExolix,
caption: ExchangeProviderDescription.exolix.title,
onChanged: () => tradeFilterStore
.toggleDisplayExchange(ExchangeProviderDescription.exolix)),
]
},
subname = '',

View file

@ -92,9 +92,8 @@ class TransactionListItem extends ActionListItem with Keyable {
break;
case WalletType.nano:
amount = calculateFiatAmountRaw(
cryptoAmount: nanoUtil!
.getRawAsDecimal(nano!.getTransactionAmountRaw(transaction).toString(), nanoUtil!.rawPerNano)
.toDouble(),
cryptoAmount: double.parse(nanoUtil!.getRawAsDecimalString(
nano!.getTransactionAmountRaw(transaction).toString(), nanoUtil!.rawPerNano)),
price: price);
break;
case WalletType.ethereum:

View file

@ -1,5 +1,4 @@
import 'dart:async';
import 'package:cake_wallet/exchange/exolix/exolix_exchange_provider.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart';
import 'package:cake_wallet/exchange/trocador/trocador_exchange_provider.dart';
@ -54,9 +53,6 @@ abstract class ExchangeTradeViewModelBase with Store {
case ExchangeProviderDescription.trocador:
_provider = TrocadorExchangeProvider();
break;
case ExchangeProviderDescription.exolix:
_provider = ExolixExchangeProvider();
break;
}
_updateItems();

View file

@ -6,8 +6,6 @@ import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/entities/wallet_contact.dart';
import 'package:cake_wallet/exchange/exolix/exolix_exchange_provider.dart';
import 'package:cake_wallet/exchange/exolix/exolix_request.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart';
@ -152,7 +150,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
SideShiftExchangeProvider(),
SimpleSwapExchangeProvider(),
TrocadorExchangeProvider(useTorOnly: _useTorOnly),
ExolixExchangeProvider(),
];
@observable
@ -549,17 +546,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
amount = isFixedRateMode ? receiveAmount : depositAmount;
}
if (provider is ExolixExchangeProvider) {
request = ExolixRequest(
from: depositCurrency,
to: receiveCurrency,
fromAmount: depositAmount.replaceAll(',', '.'),
toAmount: receiveAmount.replaceAll(',', '.'),
refundAddress: depositAddress,
address: receiveAddress);
amount = isFixedRateMode ? receiveAmount : depositAmount;
}
amount = amount.replaceAll(',', '.');
if (limitsState is LimitsLoadedSuccessfully) {

View file

@ -278,7 +278,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
List<bool> conditionsList = [];
for (var output in outputs) {
final show = checkThroughChecksToDisplayTOTP(output.address);
final show = checkThroughChecksToDisplayTOTP(output.extractedAddress);
conditionsList.add(show);
}
@ -427,9 +428,14 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
}
}
String translateErrorMessage(String error, WalletType walletType, CryptoCurrency currency,) {
String translateErrorMessage(
String error,
WalletType walletType,
CryptoCurrency currency,
) {
if (walletType == WalletType.ethereum || walletType == WalletType.haven) {
if (error.contains('gas required exceeds allowance') || error.contains('insufficient funds for')) {
if (error.contains('gas required exceeds allowance') ||
error.contains('insufficient funds for')) {
return S.current.do_not_have_enough_gas_asset(currency.toString());
}
}

View file

@ -201,38 +201,15 @@ abstract class Setup2FAViewModelBase with Store {
@observable
ObservableList<VerboseControlSettings> selected2FASettings;
//! The code here works, but can be improved
//! Still trying out various ways to improve it
@action
void selectCakePreset(Cake2FAPresetsOptions cake2FAPreset) {
// The tabs are ordered in the format [Narrow || Normal || Verbose]
// Where Narrow = 0, Normal = 1 and Verbose = 2
switch (cake2FAPreset) {
case Cake2FAPresetsOptions.narrow:
activateCake2FANarrowPreset();
break;
case Cake2FAPresetsOptions.normal:
activateCake2FANormalPreset();
break;
case Cake2FAPresetsOptions.aggressive:
activateCake2FAAggressivePreset();
break;
default:
activateCake2FANormalPreset();
}
}
@action
void checkIfTheCurrentSettingMatchesAnyOfThePresets() {
final hasNormalPreset = checkIfTheNormalPresetIsPresent();
final hasNarrowPreset = checkIfTheNarrowPresetIsPresent();
final hasVerbosePreset = checkIfTheVerbosePresetIsPresent();
if (hasNormalPreset || hasNarrowPreset || hasVerbosePreset) {
unhighlightTabs = false;
} else {
unhighlightTabs = true;
}
if (hasNormalPreset || hasNarrowPreset || hasVerbosePreset) return;
noCake2FAPresetSelected();
}
@action
@ -288,32 +265,8 @@ abstract class Setup2FAViewModelBase with Store {
}
@action
void activateCake2FANormalPreset() {
_settingsStore.selectedCake2FAPreset = Cake2FAPresetsOptions.normal;
setAllControlsToFalse();
switchShouldRequireTOTP2FAForSendsToNonContact(true);
switchShouldRequireTOTP2FAForSendsToContact(true);
switchShouldRequireTOTP2FAForSendsToInternalWallets(true);
switchShouldRequireTOTP2FAForExchangesToInternalWallets(true);
switchShouldRequireTOTP2FAForAllSecurityAndBackupSettings(true);
}
@action
void activateCake2FANarrowPreset() {
_settingsStore.selectedCake2FAPreset = Cake2FAPresetsOptions.narrow;
setAllControlsToFalse();
switchShouldRequireTOTP2FAForSendsToNonContact(true);
switchShouldRequireTOTP2FAForAddingContacts(true);
switchShouldRequireTOTP2FAForCreatingNewWallet(true);
switchShouldRequireTOTP2FAForAllSecurityAndBackupSettings(true);
}
@action
void activateCake2FAAggressivePreset() {
_settingsStore.selectedCake2FAPreset = Cake2FAPresetsOptions.aggressive;
setAllControlsToFalse();
switchShouldRequireTOTP2FAForAccessingWallet(true);
switchShouldRequireTOTP2FAForAllSecurityAndBackupSettings(true);
void noCake2FAPresetSelected() {
_settingsStore.selectedCake2FAPreset = Cake2FAPresetsOptions.none;
}
@action
@ -330,90 +283,106 @@ abstract class Setup2FAViewModelBase with Store {
unhighlightTabs = false;
}
final Map<Cake2FAPresetsOptions, List<VerboseControlSettings>> presetsMap = {
Cake2FAPresetsOptions.normal: [
VerboseControlSettings.sendsToContacts,
VerboseControlSettings.sendsToNonContacts,
VerboseControlSettings.sendsToInternalWallets,
VerboseControlSettings.securityAndBackupSettings,
VerboseControlSettings.exchangesToInternalWallets
],
Cake2FAPresetsOptions.narrow: [
VerboseControlSettings.addingContacts,
VerboseControlSettings.sendsToNonContacts,
VerboseControlSettings.creatingNewWallets,
VerboseControlSettings.securityAndBackupSettings,
],
Cake2FAPresetsOptions.aggressive: [
VerboseControlSettings.accessWallet,
VerboseControlSettings.securityAndBackupSettings,
],
Cake2FAPresetsOptions.none: [],
};
@action
void switchShouldRequireTOTP2FAForAccessingWallet(bool value) {
_settingsStore.shouldRequireTOTP2FAForAccessingWallet = value;
if (value) {
selected2FASettings.add(VerboseControlSettings.accessWallet);
} else {
selected2FASettings.remove(VerboseControlSettings.accessWallet);
}
checkIfTheCurrentSettingMatchesAnyOfThePresets();
void selectCakePreset(Cake2FAPresetsOptions preset) {
presetsMap[preset]?.forEach(toggleControl);
_settingsStore.selectedCake2FAPreset = preset;
}
@action
void toggleControl(VerboseControlSettings control, [bool value = true]) {
final methodsMap = {
VerboseControlSettings.sendsToContacts: switchShouldRequireTOTP2FAForSendsToContact,
VerboseControlSettings.accessWallet: switchShouldRequireTOTP2FAForAccessingWallet,
VerboseControlSettings.addingContacts: switchShouldRequireTOTP2FAForAddingContacts,
VerboseControlSettings.creatingNewWallets: switchShouldRequireTOTP2FAForCreatingNewWallet,
VerboseControlSettings.sendsToNonContacts: switchShouldRequireTOTP2FAForSendsToNonContact,
VerboseControlSettings.sendsToInternalWallets:
switchShouldRequireTOTP2FAForSendsToInternalWallets,
VerboseControlSettings.securityAndBackupSettings:
switchShouldRequireTOTP2FAForAllSecurityAndBackupSettings,
VerboseControlSettings.exchangesToInternalWallets:
switchShouldRequireTOTP2FAForExchangesToInternalWallets,
};
methodsMap[control]?.call(value);
}
@action
void switchShouldRequireTOTP2FAForSendsToContact(bool value) {
_settingsStore.shouldRequireTOTP2FAForSendsToContact = value;
if (value) {
selected2FASettings.add(VerboseControlSettings.sendsToContacts);
} else {
selected2FASettings.remove(VerboseControlSettings.sendsToContacts);
}
checkIfTheCurrentSettingMatchesAnyOfThePresets();
updateSelectedSettings(VerboseControlSettings.sendsToContacts, value);
}
@action
void switchShouldRequireTOTP2FAForAccessingWallet(bool value) {
_settingsStore.shouldRequireTOTP2FAForAccessingWallet = value;
updateSelectedSettings(VerboseControlSettings.accessWallet, value);
}
@action
void switchShouldRequireTOTP2FAForSendsToNonContact(bool value) {
_settingsStore.shouldRequireTOTP2FAForSendsToNonContact = value;
if (value) {
selected2FASettings.add(VerboseControlSettings.sendsToNonContacts);
} else {
selected2FASettings.remove(VerboseControlSettings.sendsToNonContacts);
}
checkIfTheCurrentSettingMatchesAnyOfThePresets();
updateSelectedSettings(VerboseControlSettings.sendsToNonContacts, value);
}
@action
void switchShouldRequireTOTP2FAForSendsToInternalWallets(bool value) {
_settingsStore.shouldRequireTOTP2FAForSendsToInternalWallets = value;
if (value) {
selected2FASettings.add(VerboseControlSettings.sendsToInternalWallets);
} else {
selected2FASettings.remove(VerboseControlSettings.sendsToInternalWallets);
}
checkIfTheCurrentSettingMatchesAnyOfThePresets();
updateSelectedSettings(VerboseControlSettings.sendsToInternalWallets, value);
}
@action
void switchShouldRequireTOTP2FAForExchangesToInternalWallets(bool value) {
_settingsStore.shouldRequireTOTP2FAForExchangesToInternalWallets = value;
if (value) {
selected2FASettings.add(VerboseControlSettings.exchangesToInternalWallets);
} else {
selected2FASettings.remove(VerboseControlSettings.exchangesToInternalWallets);
}
checkIfTheCurrentSettingMatchesAnyOfThePresets();
updateSelectedSettings(VerboseControlSettings.exchangesToInternalWallets, value);
}
@action
void switchShouldRequireTOTP2FAForAddingContacts(bool value) {
_settingsStore.shouldRequireTOTP2FAForAddingContacts = value;
if (value)
selected2FASettings.add(VerboseControlSettings.addingContacts);
else {
selected2FASettings.remove(VerboseControlSettings.addingContacts);
}
checkIfTheCurrentSettingMatchesAnyOfThePresets();
updateSelectedSettings(VerboseControlSettings.addingContacts, value);
}
@action
void switchShouldRequireTOTP2FAForCreatingNewWallet(bool value) {
_settingsStore.shouldRequireTOTP2FAForCreatingNewWallets = value;
if (value) {
selected2FASettings.add(VerboseControlSettings.creatingNewWallets);
} else {
selected2FASettings.remove(VerboseControlSettings.creatingNewWallets);
}
checkIfTheCurrentSettingMatchesAnyOfThePresets();
updateSelectedSettings(VerboseControlSettings.creatingNewWallets, value);
}
@action
void switchShouldRequireTOTP2FAForAllSecurityAndBackupSettings(bool value) {
_settingsStore.shouldRequireTOTP2FAForAllSecurityAndBackupSettings = value;
if (value)
selected2FASettings.add(VerboseControlSettings.securityAndBackupSettings);
else {
selected2FASettings.remove(VerboseControlSettings.securityAndBackupSettings);
updateSelectedSettings(VerboseControlSettings.securityAndBackupSettings, value);
}
@action
void updateSelectedSettings(VerboseControlSettings control, bool value) {
if (value) {
selected2FASettings.add(control);
} else {
selected2FASettings.remove(control);
}
checkIfTheCurrentSettingMatchesAnyOfThePresets();
}

View file

@ -53,11 +53,6 @@ abstract class SupportViewModelBase with Store {
icon: 'assets/images/simpleSwap.png',
linkTitle: 'support@simpleswap.io',
link: 'mailto:support@simpleswap.io'),
LinkListItem(
title: 'Exolix',
icon: 'assets/images/exolix.png',
linkTitle: 'support@exolix.com',
link: 'mailto:support@exolix.com'),
if (!isMoneroOnly) ... [
LinkListItem(
title: 'Wyre',

View file

@ -2,7 +2,6 @@ import 'dart:async';
import 'package:cake_wallet/exchange/changenow/changenow_exchange_provider.dart';
import 'package:cake_wallet/exchange/exchange_provider.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/exchange/exolix/exolix_exchange_provider.dart';
import 'package:cake_wallet/exchange/morphtoken/morphtoken_exchange_provider.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart';
@ -55,9 +54,6 @@ abstract class TradeDetailsViewModelBase with Store {
case ExchangeProviderDescription.trocador:
_provider = TrocadorExchangeProvider();
break;
case ExchangeProviderDescription.exolix:
_provider = ExolixExchangeProvider();
break;
}
_updateItems();
@ -161,12 +157,6 @@ abstract class TradeDetailsViewModelBase with Store {
items.add(StandartListItem(
title: '${trade.providerName} ${S.current.password}', value: trade.password ?? ''));
}
if (trade.provider == ExchangeProviderDescription.exolix) {
final buildURL = 'https://exolix.com/transaction/${trade.id.toString()}';
items.add(
TrackTradeListItem(title: 'Track', value: buildURL, onTap: () => _launchUrl(buildURL)));
}
}
void _launchUrl(String url) {

View file

@ -15,15 +15,15 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_ANDROID_TYPE=$1
MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.6.2"
MONERO_COM_BUILD_NUMBER=58
MONERO_COM_VERSION="1.7.0"
MONERO_COM_BUILD_NUMBER=61
MONERO_COM_BUNDLE_ID="com.monero.app"
MONERO_COM_PACKAGE="com.monero.app"
MONERO_COM_SCHEME="monero.com"
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.9.2"
CAKEWALLET_BUILD_NUMBER=171
CAKEWALLET_VERSION="4.10.0"
CAKEWALLET_BUILD_NUMBER=175
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
CAKEWALLET_SCHEME="cakewallet"

View file

@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_IOS_TYPE=$1
MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.6.2"
MONERO_COM_BUILD_NUMBER=56
MONERO_COM_VERSION="1.7.0"
MONERO_COM_BUILD_NUMBER=59
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.9.2"
CAKEWALLET_BUILD_NUMBER=185
CAKEWALLET_VERSION="4.10.0"
CAKEWALLET_BUILD_NUMBER=189
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
HAVEN_NAME="Haven"

View file

@ -15,8 +15,8 @@ if [ -n "$1" ]; then
fi
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="1.2.2"
CAKEWALLET_BUILD_NUMBER=33
CAKEWALLET_VERSION="1.3.0"
CAKEWALLET_BUILD_NUMBER=36
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then

View file

@ -639,6 +639,7 @@ abstract class Nano {
Future<void> changeRep(Object wallet, String address);
Future<void> updateTransactions(Object wallet);
BigInt getTransactionAmountRaw(TransactionInfo transactionInfo);
String getRepresentative(Object wallet);
}
abstract class NanoAccountList {
@ -672,8 +673,7 @@ abstract class NanoUtil {
BigInt rawPerBanano = BigInt.parse("100000000000000000000000000000");
BigInt rawPerXMR = BigInt.parse("1000000000000");
BigInt convertXMRtoNano = BigInt.parse("1000000000000000000");
Decimal getRawAsDecimal(String? raw, BigInt? rawPerCur);
String truncateDecimal(Decimal input, {int digits = maxDecimalDigits});
String getRawAsDecimalString(String? raw, BigInt? rawPerCur);
String getRawAsUsableString(String? raw, BigInt rawPerCur);
String getRawAccuracy(String? raw, BigInt rawPerCur);
String getAmountAsRaw(String amount, BigInt rawPerCur);
@ -693,7 +693,7 @@ abstract class NanoUtil {
}
""";
const nanoEmptyDefinition = 'Nano? nano;\nNanoUtil? nanoUtil = CWNanoUtil();\n';
const nanoEmptyDefinition = 'Nano? nano;\nNanoUtil? nanoUtil;\n';
const nanoCWDefinition = 'Nano? nano = CWNano();\nNanoUtil? nanoUtil = CWNanoUtil();\n';
final output = '$nanoCommonHeaders\n' +

View file

@ -32,7 +32,6 @@ class SecretKey {
SecretKey('fiatApiKey', () => ''),
SecretKey('payfuraApiKey', () => ''),
SecretKey('chatwootWebsiteToken', () => ''),
SecretKey('exolixApiKey', () => ''),
SecretKey('robinhoodApplicationId', () => ''),
SecretKey('robinhoodCIdApiSecret', () => ''),
SecretKey('walletConnectProjectId', () => ''),