Merge branch 'main' of https://github.com/cake-tech/cake_wallet into ionia-auth-ui

This commit is contained in:
Godwin Asuquo 2022-05-30 15:50:47 +02:00
commit d6c415dad2
64 changed files with 938 additions and 387 deletions

1
.gitignore vendored
View file

@ -119,6 +119,7 @@ cw_haven/android/.cxx/
lib/bitcoin/bitcoin.dart
lib/monero/monero.dart
lib/haven/haven.dart
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_180.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_120.png

View file

@ -1,6 +1,6 @@
Privacy Policy
Last modified: January 11, 2022
Last modified: April 29, 2022
Introduction
============
@ -22,34 +22,44 @@ Definitions
- "App" means any software program provided by the Company, downloaded by You on any electronic device, including but not limited to Cake Wallet and Monero.com.
- "Device" means any device that can access the App, such as a cell phone or tablet device.
- "Node" means a full Monero or Bitcoin or Litecoin Node (or any other node on a supported cryptocurrency network), which transmits data to your App for processing and synchronization, and to which your Device transmits transactions which you would like to submit to the Monero or Bitcoin or Litecoin networks (or any other supported cryptocurrency network).
- "Node" means a server on a supported cryptocurrency network which transmits data to your App for processing and synchronization, and to which your Device transmits transactions which you would like to submit to the supported cryptocurrency networks. This includes full nodes, Electrum servers, and lightning network nodes.
- "Cake Labs Nodes" refers to the set of cryptocurrency nodes operated and maintained by Cake Labs LLC.
- "Service" refers to the App.
- "Third-party Service" refers to any service integrated into the App. This includes ChangeNOW, Wyre, MoonPay, and BlockBuy.
- "Third-party Service" refers to any service integrated into the App. This includes but is not limited to ChangeNOW, Wyre, MoonPay, and BlockBuy.
- "Usage Data" refers to data collected automatically about your usage of an App.
- "You" means the individual, group, corporation, or any other entity accessing or using the Service.
Information We Collect About You and How We Collect It
------------------------------------------------------
Information We Never Receive Nor Collect
----------------------------------------
Usage Data (including the date and time at which you use an application, the duration of using it, and other metadata) is NOT collected by Cake Labs through the usage of the App. Cake Labs has no reason to care about any aspect of your continued usage of our App. We believe that this data is your own property and that we have no right to collect it.
Data relating to your funds, and their security and privacy, remains on your device at ALL times. Your private keys (including your Monero private view keys), seeds, backup files, and wallet passcode are your own responsibility. This data is not received, collected, or stored by Cake Labs at any time, for any reason.
Information We May Receive But Do Not Retain
--------------------------------------------
We receive but do NOT store information from and about users of our App, including:
- The device IP address, the block height to which your wallet is synchronized, and any transactions or channels which you use our Node to submit to supported cryptocurrency networks.
We receive this infoirmation:
- Automatically as you use the App.
This data is provided by connecting to the Nodes and price API maintained by Cake Labs. You have the right to choose not to provide synchronization data to Cake Labs by choosing a different Node. We provide a list of Nodes in the app that include our own and third party Nodes, or you can use your own Node (which we recommend).
Personal Data sent through the Cake Labs Nodes is limited to your device's IP address, the block height to which your wallet is synchronized, and any transactions or channels which you use our Node to submit to the supported cryptocurrency networks. Personal Data received by Cake Labs in this manner is not stored for any length of time, and thus Cake Labs is both unwilling to and incapable of sharing this data, or using it for any purpose beyond ensuring your appropriate connection to our Nodes.
If you decide to use a Node offered by any third party, some of which we include in our Apps, said third party will receive this Personal Data instead of Cake Labs. We take no responsibility for the actions of any third-party Node offered within the Application. We recommend connecting to your own Node to limit third party sharing of your Personal Information.
Information We May Collect About You and How We Collect It
----------------------------------------------------------
We collect several types of information from and about users of our App, including information:
- By which you may be personally identified, such as name, e-mail address, or and a/any other identifier by which you may be contacted online or offline ("personal information" or "Personal Data”), ONLY when you provide it to us;
- Device IP address, the block height to which your wallet is synchronized, and any transactions which you use our Node to submit to the Monero or Bitcoin or Litecoin networks.
We collect this information:
- Directly from you when you provide it to us.
- Automatically as you use the App, if you use one of the Cake Labs Nodes. Information collected automatically may include IP address and block height.
Usage Data (including the date and time at which you use an application, the duration of using it, and other metadata) is NOT collected by Cake Labs through the usage of the App. Cake Labs has no reason to care about any aspect of your continued usage of our App. We believe that this data is your own property and that we have no right to collect it.
Personal information is received by Cake Labs ONLY in the event that you choose to provide it to us. This is provided either by synchronizing your wallet using the Nodes maintained by Cake Labs, or by voluntarily contacting Cake Labs regarding support, questions or suggestions. You also have the right to choose not to provide data to Cake Labs, by choosing a different Node. The option to do so is provided by default with a list of Nodes, but Cake Wallet and Monero.com also provide the ability to add another Node not listed, or use your own Node.
Data relating to your funds, and their security and privacy, remains on your device at ALL times. Your private keys, seeds, backup files, and wallet passcode are your own responsibility. This data is not received, collected, or stored by Cake Labs at any time, for any reason.
Personal Data collected through the Cake Labs Nodes is limited to your device's IP address, the block height to which your wallet is synchronized, and any transactions which you use our Node to submit to the Monero or Bitcoin or Litecoin networks (or any other supported cryptocurrency network). Personal Data received by Cake Labs in this manner is not stored for any length of time, and thus Cake Labs is both unwilling to and incapable of sharing this data, or using it for any purpose beyond ensuring your appropriate connection to our Nodes.
If you decide to use a Node offered by any third party, some of which we offer by default in our Apps, said third party will receive this Personal Data instead of Cake Labs. We take no responsibility for the actions of any third-party Node offered within the Application. If you decide to synchronize your Wallet using your own Node, neither Cake Labs nor any third party will have access to this Personal Data.
In any of these situations, Cake Labs takes no responsibility for interception of this data by any outside individual, group, corporation, or institution. You should understand this and take any and all appropriate actions to secure your own data.
Personal information is received by Cake Labs ONLY in the event that you choose to provide it to us by voluntarily contacting Cake Labs regarding support, questions or suggestions.
How We Use Your Information
---------------------------
@ -76,7 +86,7 @@ Disclosure of Your Information
We may disclose personal information that we collect or you provide as described in this Privacy Policy:
- To our subsidiaries and affiliates.
- To contractors, service providers, and other third parties we use to support our business and who are bound by contractual obligations to keep personal information confidential and use it only for the purposes for which we disclose it to them.
- To a buyer or other successor in the event of a merger, divestiture, restructuring, reorganization, dissolution, or other sale or transfer of some or all of Cake Technology's assets, whether as a going concern or as part of bankruptcy, liquidation, or similar proceeding, in which personal information held by Cake Technology about our App users is among the assets transferred. However, we will provide notice before this Personal Data is transferred and becomes subject to a different Privacy Policy.
- To a buyer or other successor in the event of a merger, divestiture, restructuring, reorganization, dissolution, or other sale or transfer of some or all of Cake Labs's assets, whether as a going concern or as part of bankruptcy, liquidation, or similar proceeding, in which personal information held by Cake Labs about our App users is among the assets transferred. However, we will provide notice before this Personal Data is transferred and becomes subject to a different Privacy Policy.
- To fulfill the purpose for which you provide it.
- For any other purpose disclosed by us when you provide the information.
- With your consent.
@ -96,6 +106,8 @@ Data Security
You are responsible for your personal data, including all data related to the safety of your funds. You should take all appropriate action to protect this data. Cake Labs cannot recover any data related to your funds in the event that you lose or give away this data. Cake Labs strongly recommends that you take action to secure your funds, by writing down your seeds or keys, storing encrypted backups, and never sharing this information.
Cake Labs undertakes any and all reasonable steps possible to secure any data that you voluntarily transmit to us. However, we cannot guarantee that any outside system used to transmit this data is entirely secure and, as such, we recommend that you exercise caution when voluntarily transmitting data to us.
In any situation, Cake Labs takes no responsibility for interception of personal data by any outside individual, group, corporation, or institution. You should understand this and take any and all appropriate actions to secure your own data.
Links to Other Websites
-----------------------

View file

@ -1,6 +1,4 @@
-
uri: vault.havenprotocol.org:443
login: super
password: super
uri: nodes.havenprotocol.org:443
useSSL: true
is_default: true

BIN
assets/images/sideshift.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

BIN
assets/images/xhv_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -766,6 +766,11 @@ extern "C"
return strdup(m_wallet->getTxKey(std::string(txId)).c_str());
}
char *get_subaddress_label(uint32_t accountIndex, uint32_t addressIndex)
{
return strdup(get_current_wallet()->getSubaddressLabel(accountIndex, addressIndex).c_str());
}
#ifdef __cplusplus
}
#endif

View file

@ -120,3 +120,7 @@ typedef close_current_wallet = Void Function();
typedef on_startup = Void Function();
typedef rescan_blockchain = Void Function();
typedef get_subaddress_label = Pointer<Utf8> Function(
Int32 accountIndex,
Int32 addressIndex);

View file

@ -117,4 +117,8 @@ typedef CloseCurrentWallet = void Function();
typedef OnStartup = void Function();
typedef RescanBlockchainAsync = void Function();
typedef RescanBlockchainAsync = void Function();
typedef GetSubaddressLabel = Pointer<Utf8> Function(
int accountIndex,
int addressIndex);

View file

@ -112,6 +112,10 @@ final rescanBlockchainAsyncNative = moneroApi
.lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain')
.asFunction<RescanBlockchainAsync>();
final getSubaddressLabelNative = moneroApi
.lookup<NativeFunction<get_subaddress_label>>('get_subaddress_label')
.asFunction<GetSubaddressLabel>();
int getSyncingHeight() => getSyncingHeightNative();
bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
@ -327,3 +331,7 @@ Future<bool> isConnected() => compute(_isConnected, 0);
Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
void rescanBlockchainAsync() => rescanBlockchainAsyncNative();
String getSubaddressLabel(int accountIndex, int addressIndex) {
return convertUTF8ToString(pointer: getSubaddressLabelNative(accountIndex, addressIndex));
}

View file

@ -314,6 +314,10 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
}
}
String getSubaddressLabel(int accountIndex, int addressIndex) {
return monero_wallet.getSubaddressLabel(accountIndex, addressIndex);
}
List<MoneroTransactionInfo> _getAllTransactions(dynamic _) =>
monero_transaction_history
.getAllTransations()

View file

@ -19,6 +19,8 @@ These steps will help you configure and execute a build of CakeWallet from its s
CakeWallet cannot be built without the following packages installed on your build system.
- curl
- unzip
- automake
@ -41,9 +43,11 @@ CakeWallet cannot be built without the following packages installed on your buil
- openjdk-8-jre-headless
- clang
You may easily install them on your build system with the following command:
`$ sudo apt-get install -y unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake openjdk-8-jre-headless`
`$ sudo apt-get install -y curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake openjdk-8-jre-headless clang`
### 2. Installing Android Studio and Android toolchain

View file

@ -9,35 +9,42 @@ class YatService {
static String get apiUrl =>
YatService.isDevMode ? YatService.apiDevUrl : YatService.apiReleaseUrl;
static const apiReleaseUrl = "https://a.y.at";
static const apiDevUrl = 'https://yat.fyi';
static const apiDevUrl = 'https://a.yat.fyi';
static String lookupEmojiUrl(String emojiId) =>
"$apiUrl/emoji_id/$emojiId/payment";
static const String MONERO_SUB_ADDRESS = '0x1002';
static const String MONERO_STD_ADDRESS = '0x1001';
static const tags = {
'XMR': '0x1001,0x1002',
'XMR': "$MONERO_STD_ADDRESS,$MONERO_SUB_ADDRESS",
'BTC': '0x1003',
'LTC': '0x3fff'
'LTC': '0x1019'
};
Future<List<YatRecord>> fetchYatAddress(String emojiId, String ticker) async {
final formattedTicker = ticker.toUpperCase();
final formattedEmojiId = emojiId.replaceAll(' ', '');
final tag = tags[formattedTicker];
final uri = Uri.parse(lookupEmojiUrl(formattedEmojiId)).replace(
queryParameters: <String, dynamic>{
"tags": tags[formattedTicker]
"tags": tag
});
final yatRecords = <YatRecord>[];
try {
final response = await get(uri);
final resBody = json.decode(response.body) as Map<String, dynamic>;
final results = resBody["result"] as Map<dynamic, dynamic>;
results.forEach((dynamic key, dynamic value) {
yatRecords.add(YatRecord.fromJson(value as Map<String, dynamic>));
});
// Favour a subaddress over a standard address.
final yatRecord = (
results[MONERO_SUB_ADDRESS] ??
results[MONERO_STD_ADDRESS] ??
results[tag]) as Map<String, dynamic>;
if (yatRecord != null) {
yatRecords.add(YatRecord.fromJson(yatRecord));
}
return yatRecords;
} catch (_) {

View file

@ -343,10 +343,12 @@ Future setup(
getIt.get<AppStore>().settingsStore,
getIt.get<SendTemplateViewModel>(),
getIt.get<FiatConversionStore>(),
getIt.get<BalanceViewModel>(),
_transactionDescriptionBox));
getIt.registerFactory(
() => SendPage(sendViewModel: getIt.get<SendViewModel>()));
() => SendPage(sendViewModel: getIt.get<SendViewModel>(),
settingsViewModel: getIt.get<SettingsViewModel>()));
getIt.registerFactory(() => SendTemplatePage(
sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
@ -392,7 +394,7 @@ Future setup(
AccountListItem, void>(
(AccountListItem account, _) => MoneroAccountEditOrCreateViewModel(
monero.getAccountList(getIt.get<AppStore>().wallet),
haven.getAccountList(getIt.get<AppStore>().wallet),
haven?.getAccountList(getIt.get<AppStore>().wallet),
wallet: getIt.get<AppStore>().wallet,
accountListItem: account));

View file

@ -22,7 +22,7 @@ import 'package:encrypt/encrypt.dart' as encrypt;
const newCakeWalletMoneroUri = 'xmr-node.cakewallet.com:18081';
const cakeWalletBitcoinElectrumUri = 'electrum.cakewallet.com:50002';
const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002';
const havenDefaultNodeUri = 'vault.havenprotocol.org:443';
const havenDefaultNodeUri = 'nodes.havenprotocol.org:443';
Future defaultSettingsMigration(
{@required int version,
@ -128,6 +128,10 @@ Future defaultSettingsMigration(
await checkCurrentNodes(nodes, sharedPreferences);
break;
case 17:
await changeDefaultHavenNode(nodes);
break;
default:
break;
}
@ -452,3 +456,14 @@ Future<void> resetBitcoinElectrumServer(
await oldElectrumServer?.delete();
}
Future<void> changeDefaultHavenNode(
Box<Node> nodeSource) async {
const previousHavenDefaultNodeUri = 'vault.havenprotocol.org:443';
final havenNodes = nodeSource.values.where(
(node) => node.uriRaw == previousHavenDefaultNodeUri);
havenNodes.forEach((node) async {
node.uriRaw = havenDefaultNodeUri;
await node.save();
});
}

View file

@ -4,7 +4,7 @@ part 'template.g.dart';
@HiveType(typeId: Template.typeId)
class Template extends HiveObject {
Template({this.name, this.address, this.cryptoCurrency, this.amount});
Template({this.name,this.isCurrencySelected, this.address, this.cryptoCurrency, this.amount, this.fiatCurrency, this.amountFiat});
static const typeId = 6;
static const boxName = 'Template';
@ -20,4 +20,14 @@ class Template extends HiveObject {
@HiveField(3)
String amount;
}
@HiveField(4)
String fiatCurrency;
@HiveField(5)
bool isCurrencySelected;
@HiveField(6)
String amountFiat;
}

View file

@ -1,15 +1,15 @@
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_haven/api/balance_list.dart';
import 'package:cake_wallet/haven/haven.dart';
Future<void> updateHavenRate(FiatConversionStore fiatConversionStore) async {
final rate = getRate();
final base = rate.firstWhere((row) => row.getAssetType() == 'XUSD', orElse: () => null);
final rate = haven.getAssetRate();
final base = rate.firstWhere((row) => row.asset == 'XUSD', orElse: () => null);
rate.forEach((row) {
final cur = CryptoCurrency.fromString(row.getAssetType());
final baseRate = moneroAmountToDouble(amount: base.getRate());
final rowRate = moneroAmountToDouble(amount: row.getRate());
final cur = CryptoCurrency.fromString(row.asset);
final baseRate = moneroAmountToDouble(amount: base.rate);
final rowRate = moneroAmountToDouble(amount: row.rate);
if (cur == CryptoCurrency.xusd) {
fiatConversionStore.prices[cur] = 1.0;

View file

@ -11,6 +11,9 @@ class ExchangeProviderDescription extends EnumerableItem<int>
static const morphToken =
ExchangeProviderDescription(title: 'MorphToken', raw: 2);
static const sideShift =
ExchangeProviderDescription(title: 'SideShift', raw: 3);
static ExchangeProviderDescription deserialize({int raw}) {
switch (raw) {
case 0:
@ -19,6 +22,8 @@ class ExchangeProviderDescription extends EnumerableItem<int>
return changeNow;
case 2:
return morphToken;
case 3:
return sideShift;
default:
return null;
}

View file

@ -0,0 +1,265 @@
import 'dart:convert';
import 'package:cake_wallet/exchange/exchange_pair.dart';
import 'package:cake_wallet/exchange/exchange_provider.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart';
import 'package:cake_wallet/exchange/trade_not_created_exeption.dart';
import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/limits.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
class SideShiftExchangeProvider extends ExchangeProvider {
SideShiftExchangeProvider()
: super(
pairList: CryptoCurrency.all
.map((i) => CryptoCurrency.all
.map((k) => ExchangePair(from: i, to: k, reverse: true))
.where((c) => c != null))
.expand((i) => i)
.toList());
static const apiKey = secrets.sideShiftApiKey;
static const affiliateId = secrets.sideShiftAffiliateId;
static const apiBaseUrl = 'https://sideshift.ai/api';
static const rangePath = '/v1/pairs';
static const orderPath = '/v1/orders';
static const quotePath = '/v1/quotes';
static const permissionPath = '/v1/permissions';
static const apiHeaderKey = 'x-sideshift-secret';
@override
ExchangeProviderDescription get description =>
ExchangeProviderDescription.sideShift;
@override
Future<double> calculateAmount(
{CryptoCurrency from,
CryptoCurrency to,
double amount,
bool isFixedRateMode,
bool isReceiveAmount}) async {
try {
if (amount == 0) {
return 0.0;
}
final fromCurrency = normalizeCryptoCurrency(from);
final toCurrency = normalizeCryptoCurrency(to);
final url =
apiBaseUrl + rangePath + '/' + fromCurrency + '/' + toCurrency;
final response = await get(url);
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final rate = double.parse(responseJSON['rate'] as String);
final max = double.parse(responseJSON['max'] as String);
if (amount > max) return 0.00;
final estimatedAmount = rate * amount;
return estimatedAmount;
} catch (_) {
return 0.00;
}
}
@override
Future<bool> checkIsAvailable() async {
const url = apiBaseUrl + permissionPath;
final response = await get(url);
if (response.statusCode == 500) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['error']['message'] as String;
throw Exception('$error');
}
if (response.statusCode != 200) {
return false;
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final canCreateOrder = responseJSON['createOrder'] as bool;
final canCreateQuote = responseJSON['createQuote'] as bool;
return canCreateOrder && canCreateQuote;
}
@override
Future<Trade> createTrade(
{TradeRequest request, bool isFixedRateMode}) async {
final _request = request as SideShiftRequest;
final quoteId = await _createQuote(_request);
final url = apiBaseUrl + orderPath;
final headers = {apiHeaderKey: apiKey, 'Content-Type': 'application/json'};
final body = {
'type': 'fixed',
'quoteId': quoteId,
'affiliateId': affiliateId,
'settleAddress': _request.settleAddress,
'refundAddress': _request.refundAddress
};
final response = await post(url, headers: headers, body: json.encode(body));
if (response.statusCode != 201) {
if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['error']['message'] as String;
throw TradeNotCreatedException(description, description: error);
}
throw TradeNotCreatedException(description);
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final id = responseJSON['id'] as String;
final inputAddress = responseJSON['depositAddress']['address'] as String;
final settleAddress = responseJSON['settleAddress']['address'] as String;
return Trade(
id: id,
provider: description,
from: _request.depositMethod,
to: _request.settleMethod,
inputAddress: inputAddress,
refundAddress: settleAddress,
state: TradeState.created,
amount: _request.depositAmount,
createdAt: DateTime.now(),
);
}
Future<String> _createQuote(SideShiftRequest request) async {
final url = apiBaseUrl + quotePath;
final headers = {apiHeaderKey: apiKey, 'Content-Type': 'application/json'};
final depositMethod = normalizeCryptoCurrency(request.depositMethod);
final settleMethod = normalizeCryptoCurrency(request.settleMethod);
final body = {
'depositMethod': depositMethod,
'settleMethod': settleMethod,
'affiliateId': affiliateId,
'depositAmount': request.depositAmount,
};
final response = await post(url, headers: headers, body: json.encode(body));
if (response.statusCode != 201) {
if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['error']['message'] as String;
throw TradeNotCreatedException(description, description: error);
}
throw TradeNotCreatedException(description);
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final quoteId = responseJSON['id'] as String;
return quoteId;
}
@override
Future<Limits> fetchLimits(
{CryptoCurrency from, CryptoCurrency to, bool isFixedRateMode}) async {
final fromCurrency = normalizeCryptoCurrency(from);
final toCurrency = normalizeCryptoCurrency(to);
final url = apiBaseUrl + rangePath + '/' + fromCurrency + '/' + toCurrency;
final response = await get(url);
if (response.statusCode == 500) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['error']['message'] as String;
throw Exception('$error');
}
if (response.statusCode != 200) {
return null;
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final min = double.parse(responseJSON['min'] as String);
final max = double.parse(responseJSON['max'] as String);
return Limits(min: min, max: max);
}
@override
Future<Trade> findTradeById({@required String id}) async {
final url = apiBaseUrl + orderPath + '/' + id;
final response = await get(url);
if (response.statusCode == 404) {
throw TradeNotFoundException(id, provider: description);
}
if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['error']['message'] as String;
throw TradeNotFoundException(id,
provider: description, description: error);
}
if (response.statusCode != 200) {
return null;
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final fromCurrency = responseJSON['depositMethodId'] as String;
final from = CryptoCurrency.fromString(fromCurrency);
final toCurrency = responseJSON['settleMethodId'] as String;
final to = CryptoCurrency.fromString(toCurrency);
final inputAddress = responseJSON['depositAddress']['address'] as String;
final expectedSendAmount = responseJSON['depositAmount'].toString();
final deposits = responseJSON['deposits'] as List;
TradeState state;
if (deposits != null && deposits.isNotEmpty) {
final status = deposits[0]['status'] as String;
state = TradeState.deserialize(raw: status);
}
final expiredAtRaw = responseJSON['expiresAtISO'] as String;
final expiredAt =
expiredAtRaw != null ? DateTime.parse(expiredAtRaw).toLocal() : null;
return Trade(
id: id,
from: from,
to: to,
provider: description,
inputAddress: inputAddress,
amount: expectedSendAmount,
state: state,
expiredAt: expiredAt,
);
}
@override
bool get isAvailable => true;
@override
String get title => 'SideShift';
static String normalizeCryptoCurrency(CryptoCurrency currency) {
const bnbTitle = 'bsc';
const usdterc20 = 'usdtErc20';
switch (currency) {
case CryptoCurrency.bnb:
return bnbTitle;
case CryptoCurrency.usdterc20:
return usdterc20;
default:
return currency.title.toLowerCase();
}
}
}

View file

@ -0,0 +1,17 @@
import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cw_core/crypto_currency.dart';
class SideShiftRequest extends TradeRequest {
final CryptoCurrency depositMethod;
final CryptoCurrency settleMethod;
final String depositAmount;
final String settleAddress;
final String refundAddress;
SideShiftRequest(
{this.depositMethod,
this.settleMethod,
this.depositAmount,
this.settleAddress,
this.refundAddress,});
}

View file

@ -33,7 +33,8 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
TradeState(raw: 'waitingAuthorization', title: 'Waiting authorization');
static const failed = TradeState(raw: 'failed', title: 'Failed');
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 TradeState deserialize({String raw}) {
switch (raw) {
case 'pending':

View file

@ -295,4 +295,15 @@ class CWHaven extends Haven {
final havenWallet = wallet as HavenWallet;
return havenWallet.getTransactionAddress(accountIndex, addressIndex);
}
CryptoCurrency assetOfTransaction(TransactionInfo tx) {
final tx = transaction as HavenTransactionInfo;
final asset = CryptoCurrency.fromString(tx.assetType);
return asset;
}
List<AssetRate> getAssetRate()
=> getRate()
.map((rate) => AssetRate(rate.getAssetType(), rate.getRate()))
.toList();
}

View file

@ -1,144 +0,0 @@
import 'package:mobx/mobx.dart';
import 'package:flutter/foundation.dart';
import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/balance.dart';
import 'package:cw_core/output_info.dart';
import 'package:cake_wallet/view_model/send/output.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:hive/hive.dart';
import 'package:cw_core/get_height_by_date.dart';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:cw_haven/haven_wallet_service.dart';
import 'package:cw_haven/haven_wallet.dart';
import 'package:cw_haven/haven_transaction_info.dart';
import 'package:cw_haven/haven_transaction_history.dart';
import 'package:cw_core/account.dart' as monero_account;
import 'package:cw_haven/api/wallet.dart' as monero_wallet_api;
import 'package:cw_haven/mnemonics/english.dart';
import 'package:cw_haven/mnemonics/chinese_simplified.dart';
import 'package:cw_haven/mnemonics/dutch.dart';
import 'package:cw_haven/mnemonics/german.dart';
import 'package:cw_haven/mnemonics/japanese.dart';
import 'package:cw_haven/mnemonics/russian.dart';
import 'package:cw_haven/mnemonics/spanish.dart';
import 'package:cw_haven/mnemonics/portuguese.dart';
import 'package:cw_haven/mnemonics/french.dart';
import 'package:cw_haven/mnemonics/italian.dart';
import 'package:cw_haven/haven_transaction_creation_credentials.dart';
part 'cw_haven.dart';
Haven haven = CWHaven();
class Account {
Account({this.id, this.label});
final int id;
final String label;
}
class Subaddress {
Subaddress({this.id, this.accountId, this.label, this.address});
final int id;
final int accountId;
final String label;
final String address;
}
class HavenBalance extends Balance {
HavenBalance({@required this.fullBalance, @required this.unlockedBalance})
: formattedFullBalance = haven.formatterMoneroAmountToString(amount: fullBalance),
formattedUnlockedBalance =
haven.formatterMoneroAmountToString(amount: unlockedBalance),
super(unlockedBalance, fullBalance);
HavenBalance.fromString(
{@required this.formattedFullBalance,
@required this.formattedUnlockedBalance})
: fullBalance = haven.formatterMoneroParseAmount(amount: formattedFullBalance),
unlockedBalance = haven.formatterMoneroParseAmount(amount: formattedUnlockedBalance),
super(haven.formatterMoneroParseAmount(amount: formattedUnlockedBalance),
haven.formatterMoneroParseAmount(amount: formattedFullBalance));
final int fullBalance;
final int unlockedBalance;
final String formattedFullBalance;
final String formattedUnlockedBalance;
@override
String get formattedAvailableBalance => formattedUnlockedBalance;
@override
String get formattedAdditionalBalance => formattedFullBalance;
}
abstract class HavenWalletDetails {
@observable
Account account;
@observable
HavenBalance balance;
}
abstract class Haven {
HavenAccountList getAccountList(Object wallet);
MoneroSubaddressList getSubaddressList(Object wallet);
TransactionHistoryBase getTransactionHistory(Object wallet);
HavenWalletDetails getMoneroWalletDetails(Object wallet);
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex);
int getHeigthByDate({DateTime date});
TransactionPriority getDefaultTransactionPriority();
TransactionPriority deserializeMoneroTransactionPriority({int raw});
List<TransactionPriority> getTransactionPriorities();
List<String> getMoneroWordList(String language);
WalletCredentials createHavenRestoreWalletFromKeysCredentials({
String name,
String spendKey,
String viewKey,
String address,
String password,
String language,
int height});
WalletCredentials createHavenRestoreWalletFromSeedCredentials({String name, String password, int height, String mnemonic});
WalletCredentials createHavenNewWalletCredentials({String name, String password, String language});
Map<String, String> getKeys(Object wallet);
Object createHavenTransactionCreationCredentials({List<Output> outputs, TransactionPriority priority, String assetType});
String formatterMoneroAmountToString({int amount});
double formatterMoneroAmountToDouble({int amount});
int formatterMoneroParseAmount({String amount});
Account getCurrentAccount(Object wallet);
void setCurrentAccount(Object wallet, int id, String label);
void onStartup();
int getTransactionInfoAccountId(TransactionInfo tx);
WalletService createHavenWalletService(Box<WalletInfo> walletInfoSource);
}
abstract class MoneroSubaddressList {
ObservableList<Subaddress> get subaddresses;
void update(Object wallet, {int accountIndex});
void refresh(Object wallet, {int accountIndex});
List<Subaddress> getAll(Object wallet);
Future<void> addSubaddress(Object wallet, {int accountIndex, String label});
Future<void> setLabelSubaddress(Object wallet,
{int accountIndex, int addressIndex, String label});
}
abstract class HavenAccountList {
ObservableList<Account> get accounts;
void update(Object wallet);
void refresh(Object wallet);
List<Account> getAll(Object wallet);
Future<void> addAccount(Object wallet, {String label});
Future<void> setLabelAccount(Object wallet, {int accountIndex, String label});
}

View file

@ -126,7 +126,7 @@ Future<void> main() async {
exchangeTemplates: exchangeTemplates,
transactionDescriptions: transactionDescriptions,
secureStorage: secureStorage,
initialMigrationVersion: 16);
initialMigrationVersion: 17);
runApp(App());
} catch (e) {
runApp(MaterialApp(

View file

@ -294,4 +294,9 @@ class CWMonero extends Monero {
final moneroWallet = wallet as MoneroWallet;
return moneroWallet.getTransactionAddress(accountIndex, addressIndex);
}
String getSubaddressLabel(Object wallet, int accountIndex, int addressIndex) {
final moneroWallet = wallet as MoneroWallet;
return moneroWallet.getSubaddressLabel(accountIndex, addressIndex);
}
}

View file

@ -12,7 +12,7 @@ import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/src/widgets/collapsible_standart_list.dart';
class ContactListPage extends BasePage {
ContactListPage(this.contactListViewModel, {this.isEditable = true});
@ -62,9 +62,12 @@ class ContactListPage extends BasePage {
padding: EdgeInsets.only(top: 20.0, bottom: 20.0),
child: Observer(
builder: (_) {
return SectionStandardList(
return CollapsibleSectionList(
context: context,
sectionCount: 2,
themeColor: Theme.of(context).primaryTextTheme.title.color,
dividerThemeColor:
Theme.of(context).primaryTextTheme.caption.decorationColor,
sectionTitleBuilder: (_, int sectionIndex) {
var title = 'Contacts';
@ -73,7 +76,7 @@ class ContactListPage extends BasePage {
}
return Container(
padding: EdgeInsets.only(left: 24, bottom: 20),
padding: EdgeInsets.only(bottom: 10),
child: Text(title, style: TextStyle(fontSize: 36)));
},
itemCounter: (int sectionIndex) => sectionIndex == 0
@ -144,11 +147,10 @@ class ContactListPage extends BasePage {
child: Container(
color: Colors.transparent,
padding:
const EdgeInsets.only(left: 24, top: 16, bottom: 16, right: 24),
const EdgeInsets.only(top: 16, bottom: 16, right: 24),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
image ?? Offstage(),
Expanded(

View file

@ -23,36 +23,37 @@ class ActionButton extends StatelessWidget {
.display3
.backgroundColor;
return Container(
padding: EdgeInsets.only(top: 14, bottom: 16, left: 10, right: 10),
alignment: alignment,
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: () {
if (route?.isNotEmpty ?? false) {
Navigator.of(context, rootNavigator: true).pushNamed(route);
} else {
onClick?.call();
}
},
child: Container(
return GestureDetector(
onTap: () {
if (route?.isNotEmpty ?? false) {
Navigator.of(context, rootNavigator: true).pushNamed(route);
} else {
onClick?.call();
}
},
child: Container(
color: Colors.transparent,
padding: EdgeInsets.only(top: 14, bottom: 16, left: 10, right: 10),
alignment: alignment,
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
alignment: Alignment.center,
decoration: BoxDecoration(
shape: BoxShape.circle),
child: image,
),
),
SizedBox(height: 4),
Text(
title,
style: TextStyle(
fontSize: 10,
color: _textColor),
)
],
SizedBox(height: 4),
Text(
title,
style: TextStyle(
fontSize: 10,
color: _textColor),
)
],
),
),
);
}

View file

@ -87,6 +87,9 @@ class TradeRow extends StatelessWidget {
case ExchangeProviderDescription.morphToken:
image = Image.asset('assets/images/morph.png', height: 36, width: 36);
break;
case ExchangeProviderDescription.sideShift:
image = Image.asset('assets/images/sideshift.png', width: 36, height: 36);
break;
default:
image = null;
}

View file

@ -48,6 +48,8 @@ class CurrencyUtils {
return 'assets/images/xlm_icon.png';
case CryptoCurrency.xrp:
return 'assets/images/xrp_icon.png';
case CryptoCurrency.xhv:
return 'assets/images/xhv_logo.png';
default:
return null;
}

View file

@ -71,6 +71,9 @@ class PresentProviderPicker extends StatelessWidget {
case ExchangeProviderDescription.morphToken:
images.add(Image.asset('assets/images/morph_icon.png'));
break;
case ExchangeProviderDescription.sideShift:
images.add(Image.asset('assets/images/sideshift.png', width: 20));
break;
}
}

View file

@ -1,10 +1,12 @@
import 'dart:ui';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.dart';
import 'package:cake_wallet/src/screens/send/widgets/send_card.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/src/widgets/template_tile.dart';
import 'package:cake_wallet/view_model/send/output.dart';
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@ -26,11 +28,13 @@ import 'package:smooth_page_indicator/smooth_page_indicator.dart';
import 'package:cw_core/crypto_currency.dart';
class SendPage extends BasePage {
SendPage({@required this.sendViewModel}) : _formKey = GlobalKey<FormState>();
SendPage({@required this.sendViewModel,@required this.settingsViewModel }) : _formKey = GlobalKey<FormState>(),fiatFromSettings = settingsViewModel.fiatCurrency;
final SendViewModel sendViewModel;
final SettingsViewModel settingsViewModel;
final GlobalKey<FormState> _formKey;
final controller = PageController(initialPage: 0);
final FiatCurrency fiatFromSettings ;
bool _effectsInstalled = false;
@ -49,6 +53,12 @@ class SendPage extends BasePage {
@override
AppBarStyle get appBarStyle => AppBarStyle.transparent;
@override
void onClose(BuildContext context) {
settingsViewModel.setFiatCurrency(fiatFromSettings);
Navigator.of(context).pop();
}
@override
Widget middle(BuildContext context) => Row(
mainAxisAlignment: MainAxisAlignment.center,
@ -212,12 +222,18 @@ class SendPage extends BasePage {
return TemplateTile(
key: UniqueKey(),
to: template.name,
amount: template.amount,
from: template.cryptoCurrency,
amount: template.isCurrencySelected ? template.amount : template.amountFiat,
from: template.isCurrencySelected ? template.cryptoCurrency : template.fiatCurrency,
onTap: () async {
final fiatFromTemplate = FiatCurrency.all.singleWhere((element) => element.title == template.fiatCurrency);
final output = _defineCurrentOutput();
output.address = template.address;
output.setCryptoAmount(template.amount);
if(template.isCurrencySelected){
output.setCryptoAmount(template.amount);
}else{
settingsViewModel.setFiatCurrency(fiatFromTemplate);
output.setFiatAmount(template.amountFiat);
}
output.resetParsedAddress();
await output.fetchParsedAddress(context);
},

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@ -12,6 +13,7 @@ import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:cake_wallet/src/screens/send/widgets/prefix_currency_icon_widget.dart';
class SendTemplatePage extends BasePage {
SendTemplatePage({@required this.sendTemplateViewModel}) {
@ -142,7 +144,13 @@ class SendTemplatePage extends BasePage {
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: BaseTextFormField(
child: Focus(
onFocusChange: (hasFocus) {
if (hasFocus) {
sendTemplateViewModel.selectCurrency();
}
},
child: BaseTextFormField(
focusNode: _cryptoAmountFocus,
controller: _cryptoAmountController,
keyboardType: TextInputType.numberWithOptions(
@ -151,17 +159,14 @@ class SendTemplatePage extends BasePage {
FilteringTextInputFormatter.deny(
RegExp('[\\-|\\ ]'))
],
prefixIcon: Padding(
padding: EdgeInsets.only(top: 9),
child: Text(
sendTemplateViewModel.currency.title +
':',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
)),
),
prefixIcon: Observer(
builder: (_) => PrefixCurrencyIcon(
title: sendTemplateViewModel
.currency.title,
isSelected:
sendTemplateViewModel
.isCurrencySelected,
)),
hintText: '0.0000',
borderColor: Theme.of(context)
.primaryTextTheme
@ -179,10 +184,16 @@ class SendTemplatePage extends BasePage {
fontWeight: FontWeight.w500,
fontSize: 14),
validator:
sendTemplateViewModel.amountValidator)),
sendTemplateViewModel.amountValidator))),
Padding(
padding: const EdgeInsets.only(top: 20),
child: BaseTextFormField(
child: Focus(
onFocusChange: (hasFocus) {
if (hasFocus) {
sendTemplateViewModel.selectFiat();
}
},
child: BaseTextFormField(
focusNode: _fiatAmountFocus,
controller: _fiatAmountController,
keyboardType: TextInputType.numberWithOptions(
@ -191,16 +202,13 @@ class SendTemplatePage extends BasePage {
FilteringTextInputFormatter.deny(
RegExp('[\\-|\\ ]'))
],
prefixIcon: Padding(
padding: EdgeInsets.only(top: 9),
child: Text(
sendTemplateViewModel.fiat.title + ':',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
)),
),
prefixIcon: Observer(
builder: (_) => PrefixCurrencyIcon(
title: sendTemplateViewModel
.fiat.title,
isSelected: sendTemplateViewModel
.isFiatSelected,
)),
hintText: '0.00',
borderColor: Theme.of(context)
.primaryTextTheme
@ -217,7 +225,7 @@ class SendTemplatePage extends BasePage {
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 14),
)),
))),
],
),
)
@ -231,10 +239,13 @@ class SendTemplatePage extends BasePage {
onPressed: () {
if (_formKey.currentState.validate()) {
sendTemplateViewModel.addTemplate(
isCurrencySelected: sendTemplateViewModel.isCurrencySelected,
name: _nameController.text,
address: _addressController.text,
cryptoCurrency: sendTemplateViewModel.currency.title,
amount: _cryptoAmountController.text);
cryptoCurrency:sendTemplateViewModel.currency.title,
fiatCurrency: sendTemplateViewModel.fiat.title,
amount: _cryptoAmountController.text,
amountFiat: _fiatAmountController.text);
Navigator.of(context).pop();
}
},

View file

@ -0,0 +1,32 @@
import 'package:flutter/material.dart';
class PrefixCurrencyIcon extends StatelessWidget {
PrefixCurrencyIcon({
@required this.isSelected,
@required this.title,
});
final bool isSelected;
final String title;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.fromLTRB(0, 6.0, 8.0, 0),
child: Column(children: [
Container(
padding: EdgeInsets.symmetric(vertical: 4, horizontal: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(26),
color: isSelected ? Colors.green : Colors.transparent,
),
child: Text(title + ':',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
)),
)
]));
}
}

View file

@ -0,0 +1,92 @@
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:flutter/material.dart';
class CollapsibleSectionList extends SectionStandardList {
CollapsibleSectionList(
{bool hasTopSeparator,
BuildContext context,
int sectionCount,
int Function(int sectionIndex) itemCounter,
Widget Function(BuildContext context, int sectionIndex, int itemIndex)
itemBuilder,
Widget Function(BuildContext context, int sectionIndex)
sectionTitleBuilder,
Color themeColor,
Color dividerThemeColor})
: super(
hasTopSeparator: hasTopSeparator,
sectionCount: sectionCount,
itemCounter: itemCounter,
itemBuilder: itemBuilder,
sectionTitleBuilder: sectionTitleBuilder,
themeColor: themeColor,
dividerThemeColor: dividerThemeColor);
@override
List<Widget> transform(
bool hasTopSeparator,
BuildContext context,
int sectionCount,
int Function(int sectionIndex) itemCounter,
Widget Function(BuildContext context, int sectionIndex, int itemIndex)
itemBuilder,
Widget Function(BuildContext context, int sectionIndex)
sectionTitleBuilder,
themeColor,
dividerThemeColor) {
final items = <Widget>[];
for (var sectionIndex = 0; sectionIndex < sectionCount; sectionIndex++) {
final itemCount = itemCounter(sectionIndex);
items.add(Theme(
data: ThemeData(
textTheme: TextTheme(subtitle1: TextStyle(color: themeColor,fontFamily: 'Lato')),
backgroundColor: dividerThemeColor,
unselectedWidgetColor: themeColor,
accentColor: themeColor)
.copyWith(dividerColor: Colors.transparent),
child: Padding(
padding: const EdgeInsets.only(left: 24.0),
child: ListTileTheme(
contentPadding: EdgeInsets.only(right: 16,top:sectionIndex>0?26:0),
child: ExpansionTile(
title: sectionTitleBuilder == null
? Container()
: Container(child: buildTitle(items, sectionIndex, context)),
initiallyExpanded: true,
children: buildSection(itemCount, items, sectionIndex, context),
),
),
),
));
}
items.add(StandardListSeparator(padding: EdgeInsets.only(left: 24)));
return items;
}
@override
Widget buildTitle(
List<Widget> items, int sectionIndex, BuildContext context) {
final title = sectionTitleBuilder(context, sectionIndex);
return title;
}
@override
List<Widget> buildSection(int itemCount, List<Widget> items, int sectionIndex,
BuildContext context) {
final List<Widget> section = [];
for (var itemIndex = 0; itemIndex < itemCount; itemIndex++) {
final item = itemBuilder(context, sectionIndex, itemIndex);
section.add(StandardListSeparator());
section.add(item);
}
return section;
}
}

View file

@ -120,9 +120,20 @@ class SectionStandardList extends StatelessWidget {
@required this.sectionCount,
this.sectionTitleBuilder,
this.hasTopSeparator = false,
this.themeColor,
this.dividerThemeColor,
BuildContext context})
: totalRows = transform(hasTopSeparator, context, sectionCount,
itemCounter, itemBuilder, sectionTitleBuilder);
: totalRows = [] {
totalRows.addAll(transform(
hasTopSeparator,
context,
sectionCount,
itemCounter,
itemBuilder,
sectionTitleBuilder,
themeColor,
dividerThemeColor));
}
final int sectionCount;
final bool hasTopSeparator;
@ -132,8 +143,10 @@ class SectionStandardList extends StatelessWidget {
final Widget Function(BuildContext context, int sectionIndex)
sectionTitleBuilder;
final List<Widget> totalRows;
final Color themeColor;
final Color dividerThemeColor;
static List<Widget> transform(
List<Widget> transform(
bool hasTopSeparator,
BuildContext context,
int sectionCount,
@ -141,7 +154,9 @@ class SectionStandardList extends StatelessWidget {
Widget Function(BuildContext context, int sectionIndex, int itemIndex)
itemBuilder,
Widget Function(BuildContext context, int sectionIndex)
sectionTitleBuilder) {
sectionTitleBuilder,
Color themeColor,
Color dividerThemeColor) {
final items = <Widget>[];
for (var sectionIndex = 0; sectionIndex < sectionCount; sectionIndex++) {
@ -150,16 +165,12 @@ class SectionStandardList extends StatelessWidget {
}
if (sectionTitleBuilder != null) {
items.add(sectionTitleBuilder(context, sectionIndex));
items.add(buildTitle(items, sectionIndex, context));
}
final itemCount = itemCounter(sectionIndex);
for (var itemIndex = 0; itemIndex < itemCount; itemIndex++) {
final item = itemBuilder(context, sectionIndex, itemIndex);
items.add(item);
}
items.addAll(buildSection(itemCount, items, sectionIndex, context));
items.add(sectionIndex + 1 != sectionCount
? SectionHeaderListRow()
@ -169,6 +180,24 @@ class SectionStandardList extends StatelessWidget {
return items;
}
Widget buildTitle(
List<Widget> items, int sectionIndex, BuildContext context) {
final title = sectionTitleBuilder(context, sectionIndex);
return title;
}
List<Widget> buildSection(int itemCount, List<Widget> items, int sectionIndex,
BuildContext context) {
final List<Widget> section = [];
for (var itemIndex = 0; itemIndex < itemCount; itemIndex++) {
final item = itemBuilder(context, sectionIndex, itemIndex);
section.add(item);
}
return section;
}
@override
Widget build(BuildContext context) {
return ListView.separated(

View file

@ -23,9 +23,9 @@ abstract class SendTemplateBase with Store {
templates.replaceRange(0, templates.length, templateSource.values.toList());
@action
Future addTemplate({String name, String address, String cryptoCurrency, String amount}) async {
final template = Template(name: name, address: address,
cryptoCurrency: cryptoCurrency, amount: amount);
Future addTemplate({String name,bool isCurrencySelected, String address, String cryptoCurrency, String fiatCurrency, String amount,String amountFiat}) async {
final template = Template(name: name,isCurrencySelected: isCurrencySelected, address: address,
cryptoCurrency: cryptoCurrency, fiatCurrency: fiatCurrency, amount: amount, amountFiat: amountFiat);
await templateSource.add(template);
}

View file

@ -29,7 +29,7 @@ class YatLink {
static const startFlowUrl = ''; // 'https://www.y03btrk.com/4RQSJ/6JHXF/';
static const isDevMode = true;
static const tags = <String, List<String>>{"XMR" : ['0x1001', '0x1002'],
"BTC" : ['0x1003'], "LTC" : ['0x3fff']};
"BTC" : ['0x1003'], "LTC" : ['0x1019']};
static String get apiUrl => YatLink.isDevMode
? YatLink.apiDevUrl
@ -281,4 +281,4 @@ abstract class YatStoreBase with Store {
//return base64.encode(addressJsonBytes);
return '';
}
}
}

View file

@ -1,9 +1,7 @@
import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/mobx.dart';
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/haven/haven.dart';
@ -12,7 +10,6 @@ import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
import 'package:cw_core/keyable.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cw_haven/haven_transaction_info.dart';
class TransactionListItem extends ActionListItem with Keyable {
TransactionListItem(
@ -53,8 +50,7 @@ class TransactionListItem extends ActionListItem with Keyable {
price: price);
break;
case WalletType.haven:
final tx = transaction as HavenTransactionInfo;
final asset = CryptoCurrency.fromString(tx.assetType);
final asset = haven.assetOfTransaction(transaction);
final price = balanceViewModel.fiatConvertationStore.prices[asset];
amount = calculateFiatAmountRaw(
cryptoAmount: haven.formatterMoneroAmountToDouble(amount: transaction.amount),

View file

@ -1,3 +1,5 @@
import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/sync_status.dart';
@ -33,7 +35,7 @@ abstract class ExchangeViewModelBase with Store {
this.tradesStore, this._settingsStore) {
const excludeDepositCurrencies = [CryptoCurrency.xhv];
const excludeReceiveCurrencies = [CryptoCurrency.xlm, CryptoCurrency.xrp, CryptoCurrency.bnb, CryptoCurrency.xhv];
providerList = [ChangeNowExchangeProvider()];
providerList = [ChangeNowExchangeProvider(), SideShiftExchangeProvider()];
_initialPairBasedOnWallet();
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
@ -253,6 +255,18 @@ abstract class ExchangeViewModelBase with Store {
String amount;
CryptoCurrency currency;
if (provider is SideShiftExchangeProvider) {
request = SideShiftRequest(
depositMethod: depositCurrency,
settleMethod: receiveCurrency,
depositAmount: depositAmount?.replaceAll(',', '.'),
settleAddress: receiveAddress,
refundAddress: depositAddress,
);
amount = depositAmount;
currency = depositCurrency;
}
if (provider is XMRTOExchangeProvider) {
request = XMRTOTradeRequest(
from: depositCurrency,

View file

@ -36,6 +36,24 @@ abstract class SendTemplateViewModelBase with Store {
FiatCurrency get fiat => _settingsStore.fiatCurrency;
@observable
bool isCurrencySelected = true;
@observable
bool isFiatSelected = false;
@action
void selectCurrency () {
isCurrencySelected = true;
isFiatSelected = false;
}
@action
void selectFiat () {
isFiatSelected = true;
isCurrencySelected = false;
}
@computed
ObservableList<Template> get templates => _sendTemplateStore.templates;
@ -48,14 +66,20 @@ abstract class SendTemplateViewModelBase with Store {
void addTemplate(
{String name,
bool isCurrencySelected,
String address,
String cryptoCurrency,
String amount}) {
String fiatCurrency,
String amount,
String amountFiat}) {
_sendTemplateStore.addTemplate(
name: name,
isCurrencySelected: isCurrencySelected,
address: address,
cryptoCurrency: cryptoCurrency,
amount: amount);
fiatCurrency: fiatCurrency,
amount: amount,
amountFiat: amountFiat);
updateTemplate();
}

View file

@ -1,5 +1,6 @@
import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cake_wallet/view_model/send/output.dart';
import 'package:cake_wallet/view_model/send/send_template_view_model.dart';
@ -36,6 +37,7 @@ abstract class SendViewModelBase with Store {
this._settingsStore,
this.sendTemplateViewModel,
this._fiatConversationStore,
this.balanceViewModel,
this.transactionDescriptionBox)
: state = InitialExecutionState() {
final priority = _settingsStore.priority[_wallet.type];
@ -128,7 +130,7 @@ abstract class SendViewModelBase with Store {
PendingTransaction pendingTransaction;
@computed
String get balance => _wallet.balance[selectedCryptoCurrency].formattedAvailableBalance ?? '0.0';
String get balance => balanceViewModel.availableBalance ?? '0.0';
@computed
bool get isReadyForSend => _wallet.syncStatus is SyncedSyncStatus;
@ -160,6 +162,7 @@ abstract class SendViewModelBase with Store {
final WalletBase _wallet;
final SettingsStore _settingsStore;
final SendTemplateViewModel sendTemplateViewModel;
final BalanceViewModel balanceViewModel;
final FiatConversionStore _fiatConversationStore;
final Box<TransactionDescription> transactionDescriptionBox;

View file

@ -3,6 +3,7 @@ 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/morphtoken/morphtoken_exchange_provider.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart';
import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/xmrto/xmrto_exchange_provider.dart';
import 'package:cake_wallet/utils/date_formatter.dart';
@ -31,6 +32,9 @@ abstract class TradeDetailsViewModelBase with Store {
case ExchangeProviderDescription.morphToken:
_provider = MorphTokenExchangeProvider(trades: trades);
break;
case ExchangeProviderDescription.sideShift:
_provider = SideShiftExchangeProvider();
break;
}
items = ObservableList<StandartListItem>();
@ -102,6 +106,12 @@ abstract class TradeDetailsViewModelBase with Store {
}));
}
if (trade.provider == ExchangeProviderDescription.sideShift) {
final buildURL = 'https://sideshift.ai/orders/${trade.id.toString()}';
items.add(TrackTradeListItem(
title: 'Track', value: buildURL, onTap: () => launch(buildURL)));
}
if (trade.createdAt != null) {
items.add(StandartListItem(
title: S.current.trade_details_created_at,

View file

@ -60,6 +60,7 @@ abstract class TransactionDetailsViewModelBase with Store {
addressIndex != null) {
try {
final address = monero.getTransactionAddress(wallet, accountIndex, addressIndex);
final label = monero.getSubaddressLabel(wallet, accountIndex, addressIndex);
if (address?.isNotEmpty ?? false) {
isRecipientAddressShown = true;
@ -68,6 +69,14 @@ abstract class TransactionDetailsViewModelBase with Store {
title: S.current.transaction_details_recipient_address,
value: address));
}
if (label?.isNotEmpty ?? false) {
_items.add(
StandartListItem(
title: S.current.address_label,
value: label)
);
}
} catch (e) {
print(e.toString());
}
@ -133,7 +142,7 @@ abstract class TransactionDetailsViewModelBase with Store {
final type = wallet.type;
items.add(BlockExplorerListItem(
title: "View in Block Explorer",
title: S.current.view_in_block_explorer,
value: _explorerDescription(type),
onTap: () => launch(_explorerUrl(type, tx.id))));
@ -167,7 +176,7 @@ abstract class TransactionDetailsViewModelBase with Store {
String _explorerUrl(WalletType type, String txId) {
switch (type) {
case WalletType.monero:
return 'https://xmrchain.net/search?value=${txId}';
return 'https://monero.com/tx/${txId}';
case WalletType.bitcoin:
return 'https://www.blockchain.com/btc/tx/${txId}';
case WalletType.litecoin:
@ -182,13 +191,13 @@ abstract class TransactionDetailsViewModelBase with Store {
String _explorerDescription(WalletType type) {
switch (type) {
case WalletType.monero:
return 'View Transaction on XMRChain.net';
return S.current.view_transaction_on + 'Monero.com';
case WalletType.bitcoin:
return 'View Transaction on Blockchain.com';
return S.current.view_transaction_on + 'Blockchain.com';
case WalletType.litecoin:
return 'View Transaction on Blockchair.com';
return S.current.view_transaction_on + 'Blockchair.com';
case WalletType.haven:
return 'View Transaction on explorer.havenprotocol.org';
return S.current.view_transaction_on + 'explorer.havenprotocol.org';
default:
return '';
}

View file

@ -268,6 +268,7 @@
"new_subaddress_label_name" : "Bezeichnung",
"new_subaddress_create" : "Erstellen",
"address_label" : "Address label",
"subaddress_title" : "Unteradressenliste",
@ -442,6 +443,8 @@
"enter_your_note" : "Geben Sie Ihre Bemerkung ein…",
"note_optional" : "Bemerkung (optional)",
"note_tap_to_change" : "Bemerkung (zum Ändern tippen)",
"view_in_block_explorer" : "View in Block Explorer",
"view_transaction_on" : "View Transaction on ",
"transaction_key" : "Transaktionsschlüssel",
"confirmations" : "Bestätigungen",
"recipient_address" : "Empfängeradresse",

View file

@ -268,6 +268,7 @@
"new_subaddress_label_name" : "Label name",
"new_subaddress_create" : "Create",
"address_label" : "Address label",
"subaddress_title" : "Subaddress list",
@ -442,6 +443,8 @@
"enter_your_note" : "Enter your note…",
"note_optional" : "Note (optional)",
"note_tap_to_change" : "Note (tap to change)",
"view_in_block_explorer" : "View in Block Explorer",
"view_transaction_on" : "View Transaction on ",
"transaction_key" : "Transaction Key",
"confirmations" : "Confirmations",
"recipient_address" : "Recipient address",
@ -544,4 +547,4 @@
"setup_your_debit_card": "Set up your debit card",
"no_id_required": "No ID required. Top up and spend anywhere",
"how_to_use_card": "How to use this card"
}
}

View file

@ -268,6 +268,7 @@
"new_subaddress_label_name" : "Nombre de etiqueta",
"new_subaddress_create" : "Crear",
"address_label" : "Address label",
"subaddress_title" : "Lista de subdirecciones",
@ -442,6 +443,8 @@
"enter_your_note" : "Ingresa tu nota…",
"note_optional" : "Nota (opcional)",
"note_tap_to_change" : "Nota (toque para cambiar)",
"view_in_block_explorer" : "View in Block Explorer",
"view_transaction_on" : "View Transaction on ",
"transaction_key" : "Clave de transacción",
"confirmations" : "Confirmaciones",
"recipient_address" : "Dirección del receptor",
@ -528,4 +531,4 @@
"search": "Búsqueda",
"new_template" : "Nueva plantilla",
"electrum_address_disclaimer": "Generamos nuevas direcciones cada vez que usa una, pero las direcciones anteriores siguen funcionando"
}
}

View file

@ -1,13 +1,13 @@
{
"welcome" : "Bienvenue sur",
"cake_wallet" : "Cake Wallet",
"first_wallet_text" : "Super wallet pour Monero, Bitcoin et Litecoin",
"please_make_selection" : "Merci de faire un choix ci-dessous pour créer ou restaurer votre wallet.",
"create_new" : "Créer un Nouveau Wallet",
"restore_wallet" : "Restaurer un Wallet",
"first_wallet_text" : "Super portefeuille pour Monero, Bitcoin et Litecoin",
"please_make_selection" : "Merci de faire un choix ci-dessous pour créer ou restaurer votre portefeuille.",
"create_new" : "Créer un Nouveau Portefeuille",
"restore_wallet" : "Restaurer un Portefeuille",
"monero_com": "Monero.com par Cake Wallet",
"monero_com_wallet_text": "Super wallet pour Monero",
"monero_com_wallet_text": "Super portefeuille pour Monero",
"accounts" : "Comptes",
@ -22,7 +22,7 @@
"cancel" : "Annuler",
"ok" : "OK",
"contact_name" : "Nom de Contact",
"reset" : "Remise à zéro",
"reset" : "Réinitialiser",
"save" : "Sauvegarder",
"address_remove_contact" : "Supprimer contact",
"address_remove_content" : "Êtes vous certain de vouloir supprimer le contact sélectionné ?",
@ -52,17 +52,17 @@
"received" : "Reçus",
"sent" : "Envoyés",
"pending" : " (en attente)",
"rescan" : "Rescan",
"rescan" : "Analyser la blockchain",
"reconnect" : "Reconnecter",
"wallets" : "Wallets",
"show_seed" : "Visualiser le seed",
"show_keys" : "Visualiser seed/clefs",
"wallets" : "Portefeuilles",
"show_seed" : "Visualiser la graine",
"show_keys" : "Visualiser graine/clefs",
"address_book_menu" : "Carnet d'Adresses",
"reconnection" : "Reconnexion",
"reconnect_alert_text" : "Êtes vous certain de vouloir vous reconnecter ?",
"exchange" : "Échange",
"exchange" : "Échanger",
"clear" : "Effacer",
"refund_address" : "Adresse de Remboursement",
"change_exchange_provider" : "Changer de Plateforme d'Échange",
@ -76,8 +76,8 @@
"min_value" : "Min: ${value} ${currency}",
"max_value" : "Max: ${value} ${currency}",
"change_currency" : "Changer de Devise",
"overwrite_amount" : "Overwrite amount",
"qr_payment_amount" : "This QR code contains a payment amount. Do you want to overwrite the current value?",
"overwrite_amount" : "Écraser montant",
"qr_payment_amount" : "Ce QR code contient un montant de paiement. Voulez-vous écraser la valeur actuelle?",
"copy_id" : "Copier l'ID",
"exchange_result_write_down_trade_id" : "Merci de copier ou d'écrire l'ID d'échange pour continuer.",
@ -92,7 +92,7 @@
"offer_expires_in" : "L'Offre expire dans : ",
"trade_is_powered_by" : "Cet échange est proposé par ${provider}",
"copy_address" : "Copier l'Adresse",
"exchange_result_confirm" : "En pressant confirmer, vous enverrez ${fetchingLabel} ${from} depuis votre wallet nommé ${walletName} vers l'adresse ci-dessous. Vous pouvez aussi envoyer depuis votre wallet externe vers l'adresse/QR code ci-dessous.\n\nMerci d'appuyer sur confirmer pour continuer ou retournez en arrière pour modifier les montants.",
"exchange_result_confirm" : "En pressant confirmer, vous enverrez ${fetchingLabel} ${from} depuis votre portefeuille nommé ${walletName} vers l'adresse ci-dessous. Vous pouvez aussi envoyer depuis votre portefeuille externe vers l'adresse/QR code ci-dessous.\n\nMerci d'appuyer sur confirmer pour continuer ou retournez en arrière pour modifier les montants.",
"exchange_result_description" : "Vous devez envoyer un minimum de ${fetchingLabel} ${from} à l'adresse indiquée page suivante. Si vous envoyez un montant inférieur à ${fetchingLabel} ${from} il pourrait ne pas être converti et ne pas être remboursé.",
"exchange_result_write_down_ID" : "*Merci de copier ou écrire votre ID présenté ci-dessus.",
"confirm" : "Confirmer",
@ -103,19 +103,19 @@
"expired" : "Expirée",
"time" : "${minutes}m ${seconds}s",
"send_xmr" : "Envoyer XMR",
"exchange_new_template" : "Nouveau modèle",
"exchange_new_template" : "Nouveau modèle d'échange",
"faq" : "FAQ",
"enter_your_pin" : "Entrez votre code PIN",
"loading_your_wallet" : "Chargement de votre wallet",
"loading_your_wallet" : "Chargement de votre portefeuille",
"new_wallet" : "Nouveau Wallet",
"wallet_name" : "Nom du Wallet",
"new_wallet" : "Nouveau Portefeuille",
"wallet_name" : "Nom du Portefeuille",
"continue_text" : "Continuer",
"choose_wallet_currency" : "Merci de choisir la devise du wallet :",
"choose_wallet_currency" : "Merci de choisir la devise du portefeuille :",
"node_new" : "Nouveau Nœud",
@ -140,8 +140,8 @@
"new_node_testing" : "Test du nouveau nœud",
"use" : "Changer ver ",
"digit_pin" : "-digit PIN",
"use" : "Changer vers code PIN à ",
"digit_pin" : " chiffres",
"share_address" : "Partager l'adresse",
@ -155,39 +155,39 @@
"accounts_subaddresses" : "Comptes et sous-adresses",
"restore_restore_wallet" : "Restaurer le Wallet",
"restore_title_from_seed_keys" : "Restaurer depuis un seed ou des clefs",
"restore_description_from_seed_keys" : "Restaurez votre wallet depuis un seed ou des clefs que vous avez stockés en lieu sûr",
"restore_restore_wallet" : "Restaurer le Portefeuille",
"restore_title_from_seed_keys" : "Restaurer depuis une graine ou des clefs",
"restore_description_from_seed_keys" : "Restaurez votre portefeuille depuis une graine ou des clefs que vous avez stockés en lieu sûr",
"restore_next" : "Suivant",
"restore_title_from_backup" : "Restaurer depuis une sauvegarde",
"restore_description_from_backup" : "Vous pouvez restaurer l'intégralité de l'application Cake Wallet depuis un fichier de sauvegarde",
"restore_seed_keys_restore" : "Restaurer depuis Seed/Clefs",
"restore_title_from_seed" : "Restaurer depuis seed",
"restore_description_from_seed" : "Restaurez votre wallet depuis une combinaison de 25 ou 13 mots",
"restore_seed_keys_restore" : "Restaurer depuis Graine/Clefs",
"restore_title_from_seed" : "Restaurer depuis graine",
"restore_description_from_seed" : "Restaurez votre portefeuille depuis une combinaison de 25 ou 13 mots",
"restore_title_from_keys" : "Restaurer depuis des clefs",
"restore_description_from_keys" : "Restaurer votre wallet d'après les séquences de touches générées d'après vos clefs privées",
"restore_wallet_name" : "Nom du wallet",
"restore_description_from_keys" : "Restaurer votre portefeuille d'après les séquences de touches générées d'après vos clefs privées",
"restore_wallet_name" : "Nom du portefeuille",
"restore_address" : "Adresse",
"restore_view_key_private" : "Clef d'audit (view key) (privée)",
"restore_spend_key_private" : "Clef de dépense (spend key) (privée)",
"restore_recover" : "Restaurer",
"restore_wallet_restore_description" : "Description de la restauration de wallet",
"restore_new_seed" : "Nouveau seed",
"restore_active_seed" : "Seed actif",
"restore_bitcoin_description_from_seed" : "Restaurer votre wallet à l'aide d'une combinaison de 24 mots",
"restore_bitcoin_description_from_keys" : "Restaurer votre wallet d'après la chaîne WIF générée d'après vos clefs privées",
"restore_wallet_restore_description" : "Description de la restauration de portefeuille",
"restore_new_seed" : "Nouvelle graine",
"restore_active_seed" : "Graine actif",
"restore_bitcoin_description_from_seed" : "Restaurer votre portefeuille à l'aide d'une combinaison de 24 mots",
"restore_bitcoin_description_from_keys" : "Restaurer votre portefeuille d'après la chaîne WIF générée d'après vos clefs privées",
"restore_bitcoin_title_from_keys" : "Restaurer depuis la chaîne WIF",
"restore_from_date_or_blockheight" : "Merci d'entrer une date antérieure de quelques jours à la date de création de votre wallet. Ou si vous connaissez la hauteur de bloc, merci de la spécifier plutôt qu'une date",
"restore_from_date_or_blockheight" : "Merci d'entrer une date antérieure de quelques jours à la date de création de votre portefeuille. Ou si vous connaissez la hauteur de bloc, merci de la spécifier plutôt qu'une date",
"seed_reminder" : "Merci d'écrire votre seed au cas où vous perdriez ou effaceriez votre téléphone",
"seed_title" : "Seed",
"seed_share" : "Partager le seed",
"seed_reminder" : "Merci d'écrire votre graine au cas où vous perdriez ou effaceriez votre téléphone",
"seed_title" : "Graine",
"seed_share" : "Partager la graine",
"copy" : "Copier",
"seed_language_choose" : "Merci de choisir la langue du seed :",
"seed_choose" : "Choisissez la langue du seed",
"seed_language_choose" : "Merci de choisir la langue de la graine :",
"seed_choose" : "Choisissez la langue de la graine",
"seed_language_next" : "Suivant",
"seed_language_english" : "Anglais",
"seed_language_chinese" : "Chinois",
@ -202,16 +202,16 @@
"send_title" : "Envoyer",
"send_your_wallet" : "Votre wallet",
"send_your_wallet" : "Votre portefeuille",
"send_address" : "adresse ${cryptoCurrency}",
"send_payment_id" : "ID de paiement (optionnel)",
"all" : "TOUS",
"all" : "TOUT",
"send_error_minimum_value" : "La valeur minimale du montant est 0.01",
"send_error_currency" : "La monnaie ne peut contenir que des nombres",
"send_estimated_fee" : "Estimation des frais :",
"send_priority" : "Actuellement les frais sont positionnés à la priorité ${transactionPriority}.\nLa priorité de la transaction peut être modifiée dans les réglages",
"send_creating_transaction" : "Création de la transaction",
"send_templates" : "Modèles",
"send_templates" : "Modèles d'envois",
"send_new" : "Nouveau",
"send_amount" : "Montant :",
"send_fee" : "Frais :",
@ -224,7 +224,7 @@
"settings_title" : "Réglages",
"settings_nodes" : "Nœuds",
"settings_current_node" : "Nœud actuel",
"settings_wallets" : "Wallets",
"settings_wallets" : "Portefeuilles",
"settings_display_balance_as" : "Afficher le solde en",
"settings_currency" : "Devise",
"settings_fee_priority" : "Priorité des frais",
@ -251,8 +251,8 @@
"setup_successful" : "Votre code PIN a été configuré avec succès !",
"wallet_keys" : "Seed/Clefs du wallet",
"wallet_seed" : "Seed du wallet",
"wallet_keys" : "Graine/Clefs du portefeuille",
"wallet_seed" : "Graine du portefeuille",
"private_key" : "Clef privée",
"public_key" : "Clef publique",
"view_key_private" : "Clef d'audit (view key) (privée)",
@ -266,6 +266,7 @@
"new_subaddress_label_name" : "Nom",
"new_subaddress_create" : "Créer",
"address_label" : "Étiquette de l'adresse",
"subaddress_title" : "Liste des sous-adresses",
@ -293,21 +294,21 @@
"transaction_details_recipient_address" : "Adresse du bénéficiaire",
"wallet_list_title" : "Monero Wallet",
"wallet_list_create_new_wallet" : "Créer un Nouveau Wallet",
"wallet_list_restore_wallet" : "Restaurer un Wallet",
"wallet_list_load_wallet" : "Charger wallet",
"wallet_list_loading_wallet" : "Chargement du wallet ${wallet_name}",
"wallet_list_failed_to_load" : "Échec de chargement du wallet ${wallet_name}. ${error}",
"wallet_list_removing_wallet" : "Suppression du wallet ${wallet_name}",
"wallet_list_failed_to_remove" : "Échec de la suppression du wallet ${wallet_name}. ${error}",
"wallet_list_title" : "Portefeuille Monero",
"wallet_list_create_new_wallet" : "Créer un Nouveau Portefeuille",
"wallet_list_restore_wallet" : "Restaurer un Portefeuille",
"wallet_list_load_wallet" : "Charger Portefeuille",
"wallet_list_loading_wallet" : "Chargement du portefeuille ${wallet_name}",
"wallet_list_failed_to_load" : "Échec de chargement du portefeuille ${wallet_name}. ${error}",
"wallet_list_removing_wallet" : "Suppression du portefeuille ${wallet_name}",
"wallet_list_failed_to_remove" : "Échec de la suppression du portefeuille ${wallet_name}. ${error}",
"widgets_address" : "Adresse",
"widgets_restore_from_blockheight" : "Restaurer depuis une hauteur de bloc",
"widgets_restore_from_date" : "Restaurer depuis une date",
"widgets_or" : "ou",
"widgets_seed" : "Seed",
"widgets_seed" : "Graine",
"router_no_route" : "Aucune route définie pour ${name}",
@ -315,7 +316,7 @@
"error_text_account_name" : "Le nom de compte ne peut contenir que des lettres et des chiffres\net sa longueur doit être comprise entre 1 et 15 caractères",
"error_text_contact_name" : "Un nom de contact ne peut pas contenir les symboles ` , ' \"\net doit faire entre 1 et 32 caractères",
"error_text_address" : "L'adresse de wallet doit correspondre au type de\ncryptomonnaie",
"error_text_address" : "L'adresse du portefeuille doit correspondre au type de\ncryptomonnaie",
"error_text_node_address" : "Merci d'entrer une adresse IPv4",
"error_text_node_port" : "Le port d'un nœud doit être un nombre compris entre 0 et 65535",
"error_text_payment_id" : "Un ID de paiement ne peut être constitué que de 16 à 64 caractères hexadécimaux",
@ -323,8 +324,8 @@
"error_text_fiat" : "La valeur du montant ne peut dépasser le solde disponible.\nLa partie décimale doit comporter au plus 2 chiffres",
"error_text_subaddress_name" : "Le nom de sous-adresse ne peut contenir les symboles ` , ' \"\net sa longueur doit être comprise entre 1 et 20 caractères",
"error_text_amount" : "Le montant ne peut comporter que des nombres",
"error_text_wallet_name" : "Le nom du wallet ne peut contenir que des lettres et des chiffres\net sa longueur doit être comprise entre 1 et 15 caractères",
"error_text_keys" : "Les clefs du wallet ne peuvent être constituées que de 64 caractères hexadécimaux",
"error_text_wallet_name" : "Le nom du portefeuille ne peut contenir que des lettres et des chiffres\net sa longueur doit être comprise entre 1 et 15 caractères",
"error_text_keys" : "Les clefs du portefeuille ne peuvent être constituées que de 64 caractères hexadécimaux",
"error_text_crypto_currency" : "La partie décimale\ndoit comporter au plus 12 chiffres",
"error_text_minimal_limit" : "Échange pour ${provider} non créé. Le montant est inférieur au minimum : ${min} ${currency}",
"error_text_maximum_limit" : "Échange pour ${provider} non créé. Le montant est supérieur au maximum : ${max} ${currency}",
@ -336,8 +337,8 @@
"auth_store_banned_for" : "Banni pour ",
"auth_store_banned_minutes" : " minutes",
"auth_store_incorrect_password" : "Mauvais code PIN",
"wallet_store_monero_wallet" : "Wallet Monero",
"wallet_restoration_store_incorrect_seed_length" : "Longueur de seed incorrecte",
"wallet_store_monero_wallet" : "Portefeuille Monero",
"wallet_restoration_store_incorrect_seed_length" : "Longueur de graine incorrecte",
"full_balance" : "Solde Complet",
@ -386,7 +387,7 @@
"change_language_to" : "Changer la langue vers ${language}?",
"paste" : "Coller",
"restore_from_seed_placeholder" : "Merci d'entrer ou de coller votre seed ici",
"restore_from_seed_placeholder" : "Merci d'entrer ou de coller votre graine ici",
"add_new_word" : "Ajouter un nouveau mot",
"incorrect_seed" : "Le texte entré est invalide.",
@ -405,26 +406,26 @@
"template" : "Modèle",
"confirm_delete_template" : "Cette action va supprimer ce modèle. Souhaitez-vous continuer ?",
"confirm_delete_wallet" : "Cette action va supprimer ce wallet. Souhaitez-vous contnuer ?",
"confirm_delete_wallet" : "Cette action va supprimer ce portefeuille. Souhaitez-vous contnuer ?",
"picker_description" : "Pour choisir ChangeNOW ou MorphToken, merci de modifier d'abord la paire de votre échange",
"change_wallet_alert_title" : "Changer le wallet actuel",
"change_wallet_alert_content" : "Souhaitez-vous changer le wallet actuel vers ${wallet_name}?",
"change_wallet_alert_title" : "Changer le portefeuille actuel",
"change_wallet_alert_content" : "Souhaitez-vous changer le portefeuille actuel vers ${wallet_name}?",
"creating_new_wallet" : "Création d'un nouveau wallet",
"creating_new_wallet" : "Création d'un nouveau portefeuille",
"creating_new_wallet_error" : "Erreur : ${description}",
"seed_alert_title" : "Attention",
"seed_alert_content" : "Le seed est la seule façon de restaurer votre wallet. L'avez-vous correctement écrit ?",
"seed_alert_content" : "La graine est la seule façon de restaurer votre portefeuille. L'avez-vous correctement écrit ?",
"seed_alert_back" : "Retour",
"seed_alert_yes" : "Oui, je suis sûr",
"exchange_sync_alert_content" : "Merci d'attendre que votre wallet soit synchronisé",
"exchange_sync_alert_content" : "Merci d'attendre que votre portefeuille soit synchronisé",
"pre_seed_title" : "IMPORTANT",
"pre_seed_description" : "Sur la page suivante vous allez voir une série de ${words} mots. Ils constituent votre seed unique et privé et sont le SEUL moyen de restaurer votre wallet en cas de perte ou de dysfonctionnement. Il est de VOTRE responsabilité d'écrire cette série de mots et de les stocker dans un lieu sûr en dehors de l'application Cake Wallet.",
"pre_seed_button_text" : "J'ai compris. Montrez moi mon seed",
"pre_seed_description" : "Sur la page suivante vous allez voir une série de ${words} mots. Ils constituent votre graine unique et privé et sont le SEUL moyen de restaurer votre portefeuille en cas de perte ou de dysfonctionnement. Il est de VOTRE responsabilité d'écrire cette série de mots et de les stocker dans un lieu sûr en dehors de l'application Cake Wallet.",
"pre_seed_button_text" : "J'ai compris. Montrez moi ma graine",
"xmr_to_error" : "Erreur XMR.TO",
"xmr_to_error_description" : "Montant invalide. La partie décimale doit contenir au plus 8 chiffres",
@ -440,6 +441,8 @@
"enter_your_note" : "Entrez votre note…",
"note_optional" : "Note (optionnelle)",
"note_tap_to_change" : "Note (appuyez pour changer)",
"view_in_block_explorer" : "Voir dans l'Explorateur de Blocs",
"view_transaction_on" : "Voir la Transaction sur ",
"transaction_key" : "Clef de Transaction",
"confirmations" : "Confirmations",
"recipient_address" : "Adresse bénéficiaire",
@ -471,17 +474,17 @@
"xlm_extra_info" : "Merci de ne pas oublier de spécifier l'ID de mémo lors de l'envoi de la transaction XLM de l'échange",
"xrp_extra_info" : "Merci de ne pas oublier de spécifier le tag de destination lors de l'envoi de la transaction XRP de l'échange",
"exchange_incorrect_current_wallet_for_xmr" : "Si vous souhaitez échanger des XMR du solde Monero de votre Cake Wallet, merci de sélectionner votre wallet Monero au préalable.",
"exchange_incorrect_current_wallet_for_xmr" : "Si vous souhaitez échanger des XMR du solde Monero de votre Cake Wallet, merci de sélectionner votre portefeuille Monero au préalable.",
"confirmed" : "Confirmé",
"unconfirmed" : "Non confirmé",
"displayable" : "Affichable",
"displayable" : "Visible",
"submit_request" : "soumettre une requête",
"buy_alert_content" : "Pour le moment nous ne supportons que l'achat de Bitcoin et Litecoin. Pour acheter du Bitcoin ou du Litecoin, merci de créer ou de sélectionner votre wallet Bitcoin ou Litecoin.",
"sell_alert_content": "Pour le moment nous ne supportons que la vente de Bitcoin. Pour vendre du Bitcoin, merci de créer ou de sélectionner votre wallet Bitcoint.",
"buy_alert_content" : "Pour le moment nous ne supportons que l'achat de Bitcoin et Litecoin. Pour acheter du Bitcoin ou du Litecoin, merci de créer ou de sélectionner votre portefeuille Bitcoin ou Litecoin.",
"sell_alert_content": "Pour le moment nous ne supportons que la vente de Bitcoin. Pour vendre du Bitcoin, merci de créer ou de sélectionner votre portefeuille Bitcoint.",
"outdated_electrum_wallet_description" : "Les nouveaux wallet Bitcoin créés dans Cake ont dorénavant un seed de 24 mots. Il est impératif que vous créiez un nouveau wallet Bitcoin, que vous y transfériez tous vos fonds puis que vous cessiez d'utiliser le wallet avec un seed de 12 mots. Merci de faire cela immédiatement pour assurer la sécurité de vos avoirs.",
"outdated_electrum_wallet_description" : "Les nouveaux portefeuilles Bitcoin créés dans Cake ont dorénavant une graine de 24 mots. Il est impératif que vous créiez un nouveau portefeuille Bitcoin, que vous y transfériez tous vos fonds puis que vous cessiez d'utiliser le portefeuille avec une graine de 12 mots. Merci de faire cela immédiatement pour assurer la sécurité de vos avoirs.",
"understand" : "J'ai compris",
"apk_update" : "Mise à jour d'APK",
@ -490,7 +493,7 @@
"buy_with" : "Acheter avec",
"moonpay_alert_text" : "Le montant doit être au moins égal à ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "Si ce wallet a un seed de 12 mots et a été créé dans Cake, NE PAS y déposer de Bitcoin. Tous les BTC transférés vers ce wallet seront perdus. Créez un nouveau wallet avec seed de 24 mots (appuyez sur le menu en haut à droite, sélectionnez Wallets puis Créer un Nouveau Wallet et enfin Bitcoin) et transférez y IMMÉDIATEMENT vos BTC. Les nouveaux wallets BTC Cake (avec seed de 24 mots) sont sécurisés",
"outdated_electrum_wallet_receive_warning": "Si ce portefeuille a une graine de 12 mots et a été créé dans Cake, NE PAS y déposer de Bitcoin. Tous les BTC transférés vers ce portefeuille seront perdus. Créez un nouveau portefeuille avec graine de 24 mots (appuyez sur le menu en haut à droite, sélectionnez Portefeuilles puis Créer un Nouveau Portefeuille et enfin Bitcoin) et transférez y IMMÉDIATEMENT vos BTC. Les nouveaux portefeuilles BTC Cake (avec graine de 24 mots) sont sécurisés",
"do_not_show_me": "Ne plus me montrer ceci à l'avenir",
"unspent_coins_title" : "Pièces (coins) non dépensées",
@ -516,7 +519,7 @@
"yat_error" : "Erreur Yat",
"yat_error_content" : "Aucune adresse associée à ce Yat. Essayez un autre Yat",
"choose_address" : "\n\nMerci de choisir l'adresse :",
"yat_popup_title" : "L'adresse de votre wallet peut être emojifiée.",
"yat_popup_title" : "L'adresse de votre portefeuille peut être emojifiée.",
"yat_popup_content" : "Vous pouvez à présent envoyer et recevoir des cryptos dans Cake Wallet à l'aide de votre Yat - un nom d'utilisateur court à base d'emoji. Gérér les Yats à tout moment depuis l'écran de paramétrage",
"second_intro_title" : "Une adresse emoji pour les gouverner tous",
"second_intro_content" : "Votre Yat est une seule et unique adresse emoji qui remplace toutes vos longues adresses hexadécimales pour toutes vos cryptomonnaies.",

View file

@ -268,6 +268,7 @@
"new_subaddress_label_name" : "लेबल का नाम",
"new_subaddress_create" : "सर्जन करना",
"address_label" : "Address label",
"subaddress_title" : "उपखंड सूची",
@ -442,6 +443,8 @@
"enter_your_note" : "अपना नोट दर्ज करें ...",
"note_optional" : "नोट (वैकल्पिक)",
"note_tap_to_change" : "नोट (टैप टू चेंज)",
"view_in_block_explorer" : "View in Block Explorer",
"view_transaction_on" : "View Transaction on ",
"transaction_key" : "लेन-देन की",
"confirmations" : "पुष्टिकरण",
"recipient_address" : "प्राप्तकर्ता का पता",
@ -528,4 +531,4 @@
"search": "खोज",
"new_template" : "नया टेम्पलेट",
"electrum_address_disclaimer": "हर बार जब आप एक का उपयोग करते हैं तो हम नए पते उत्पन्न करते हैं, लेकिन पिछले पते काम करना जारी रखते हैं"
}
}

View file

@ -268,6 +268,7 @@
"new_subaddress_label_name" : "Oznaka",
"new_subaddress_create" : "Izradi",
"address_label" : "Address label",
"subaddress_title" : "Lista podadresa",
@ -442,6 +443,8 @@
"enter_your_note" : "Unesite svoju poruku…",
"note_optional" : "Poruka (nije obvezno)",
"note_tap_to_change" : "Poruka (dodirnite za promjenu)",
"view_in_block_explorer" : "View in Block Explorer",
"view_transaction_on" : "View Transaction on ",
"transaction_key" : "Transakcijski ključ",
"confirmations" : "Potvrde",
"recipient_address" : "Primateljeva adresa",
@ -528,4 +531,4 @@
"search": "Traži",
"new_template" : "novi predložak",
"electrum_address_disclaimer": "Minden egyes alkalommal új címeket generálunk, de a korábbi címek továbbra is működnek"
}
}

View file

@ -268,6 +268,7 @@
"new_subaddress_label_name" : "Nome etichetta",
"new_subaddress_create" : "Crea",
"address_label" : "Address label",
"subaddress_title" : "Lista sottoindirizzi",
@ -442,6 +443,8 @@
"enter_your_note" : "Inserisci la tua nota…",
"note_optional" : "Nota (opzionale)",
"note_tap_to_change" : "Nota (clicca per cambiare)",
"view_in_block_explorer" : "View in Block Explorer",
"view_transaction_on" : "View Transaction on ",
"transaction_key" : "Chiave Transazione",
"confirmations" : "Conferme",
"recipient_address" : "Indirizzo di destinazione",
@ -528,4 +531,4 @@
"search": "Ricerca",
"new_template" : "Nuovo modello",
"electrum_address_disclaimer": "Generiamo nuovi indirizzi ogni volta che ne utilizzi uno, ma gli indirizzi precedenti continuano a funzionare"
}
}

View file

@ -268,6 +268,7 @@
"new_subaddress_label_name" : "ラベル名",
"new_subaddress_create" : "作成する",
"address_label" : "Address label",
"subaddress_title" : "サブアドレス一覧",
@ -442,6 +443,8 @@
"enter_your_note" : "メモを入力してください…",
"note_optional" : "注(オプション)",
"note_tap_to_change" : "注(タップして変更)",
"view_in_block_explorer" : "View in Block Explorer",
"view_transaction_on" : "View Transaction on ",
"transaction_key" : "トランザクションキー",
"confirmations" : "確認",
"recipient_address" : "受信者のアドレス",
@ -528,4 +531,4 @@
"search": "検索",
"new_template" : "新しいテンプレート",
"electrum_address_disclaimer": "使用するたびに新しいアドレスが生成されますが、以前のアドレスは引き続き機能します"
}
}

View file

@ -268,6 +268,7 @@
"new_subaddress_label_name" : "라벨 이름",
"new_subaddress_create" : "몹시 떠들어 대다",
"address_label" : "Address label",
"subaddress_title" : "하위 주소 목록",
@ -442,6 +443,8 @@
"enter_your_note" : "메모를 입력하세요…",
"note_optional" : "참고 (선택 사항)",
"note_tap_to_change" : "메모 (변경하려면 탭하세요)",
"view_in_block_explorer" : "View in Block Explorer",
"view_transaction_on" : "View Transaction on ",
"transaction_key" : "거래 키",
"confirmations" : "확인",
"recipient_address" : "받는 사람 주소",
@ -528,4 +531,4 @@
"search": "찾다",
"new_template" : "새 템플릿",
"electrum_address_disclaimer": "사용할 때마다 새 주소가 생성되지만 이전 주소는 계속 작동합니다."
}
}

View file

@ -268,6 +268,7 @@
"new_subaddress_label_name" : "Label naam",
"new_subaddress_create" : "Creëren",
"address_label" : "Address label",
"subaddress_title" : "Subadreslijst",
@ -442,6 +443,8 @@
"enter_your_note" : "Voer uw notitie in ...",
"note_optional" : "Opmerking (optioneel)",
"note_tap_to_change" : "Opmerking (tik om te wijzigen)",
"view_in_block_explorer" : "View in Block Explorer",
"view_transaction_on" : "View Transaction on ",
"transaction_key" : "Transactiesleutel",
"confirmations" : "Bevestigingen",
"recipient_address" : "Adres ontvanger",
@ -528,4 +531,4 @@
"search": "Zoekopdracht",
"new_template" : "Nieuwe sjabloon",
"electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work"
}
}

View file

@ -271,6 +271,7 @@
"new_subaddress_label_name" : "Nazwa etykiety",
"new_subaddress_create" : "Stwórz",
"address_label" : "Address label",
"subaddress_title" : "Lista podadresów",
@ -445,6 +446,8 @@
"enter_your_note" : "Wpisz notatkę…",
"note_optional" : "Notatka (opcjonalnie)",
"note_tap_to_change" : "Notatka (dotknij, aby zmienić)",
"view_in_block_explorer" : "View in Block Explorer",
"view_transaction_on" : "View Transaction on ",
"transaction_key" : "Klucz transakcji",
"confirmations" : "Potwierdzenia",
"recipient_address" : "Adres odbiorcy",
@ -531,4 +534,4 @@
"search": "Szukaj",
"new_template" : "Nowy szablon",
"electrum_address_disclaimer": "Za każdym razem, gdy korzystasz z jednego z nich, generujemy nowe adresy, ale poprzednie adresy nadal działają"
}
}

View file

@ -268,6 +268,7 @@
"new_subaddress_label_name" : "Nome",
"new_subaddress_create" : "Criar",
"address_label" : "Address label",
"subaddress_title" : "Sub-endereços",
@ -442,6 +443,8 @@
"enter_your_note" : "Insira sua nota ...",
"note_optional" : "Nota (opcional)",
"note_tap_to_change" : "Nota (toque para alterar)",
"view_in_block_explorer" : "View in Block Explorer",
"view_transaction_on" : "View Transaction on ",
"transaction_key" : "Chave de transação",
"confirmations" : "Confirmações",
"recipient_address" : "Endereço do destinatário",
@ -528,4 +531,4 @@
"search": "Procurar",
"new_template" : "Novo modelo",
"electrum_address_disclaimer": "Geramos novos endereços cada vez que você usa um, mas os endereços anteriores continuam funcionando"
}
}

View file

@ -268,6 +268,7 @@
"new_subaddress_label_name" : "Имя",
"new_subaddress_create" : "Создать",
"address_label" : "Address label",
"subaddress_title" : "Список субадресов",
@ -442,6 +443,8 @@
"enter_your_note" : "Введите примечание…",
"note_optional" : "Примечание (необязательно)",
"note_tap_to_change" : "Примечание (нажмите для изменения)",
"view_in_block_explorer" : "View in Block Explorer",
"view_transaction_on" : "View Transaction on ",
"transaction_key" : "Ключ транзакции",
"confirmations" : "Подтверждения",
"recipient_address" : "Адрес получателя",
@ -528,4 +531,4 @@
"search": "Поиск",
"new_template" : "Новый шаблон",
"electrum_address_disclaimer": "Мы генерируем новые адреса каждый раз, когда вы их используете, но предыдущие адреса продолжают работать."
}
}

View file

@ -267,6 +267,7 @@
"new_subaddress_label_name" : "Ім'я",
"new_subaddress_create" : "Створити",
"address_label" : "Address label",
"subaddress_title" : "Список Субадрес",
@ -441,6 +442,8 @@
"enter_your_note" : "Введіть примітку…",
"note_optional" : "Примітка (необов’язково)",
"note_tap_to_change" : "Примітка (натисніть для зміни)",
"view_in_block_explorer" : "View in Block Explorer",
"view_transaction_on" : "View Transaction on ",
"transaction_key" : "Ключ транзакції",
"confirmations" : "Підтвердження",
"recipient_address" : "Адреса одержувача",
@ -527,4 +530,4 @@
"search": "Пошук",
"new_template" : "Новий шаблон",
"electrum_address_disclaimer": "Ми створюємо нові адреси щоразу, коли ви використовуєте їх, але попередні адреси продовжують працювати"
}
}

View file

@ -268,6 +268,7 @@
"new_subaddress_label_name" : "标签名称",
"new_subaddress_create" : "创建",
"address_label" : "Address label",
"subaddress_title" : "子地址列表",
@ -441,6 +442,8 @@
"enter_your_note" : "输入您的笔记...",
"note_optional" : "注释(可选)",
"note_tap_to_change" : "注释(轻按即可更改)",
"view_in_block_explorer" : "View in Block Explorer",
"view_transaction_on" : "View Transaction on ",
"transaction_key" : "交易密码",
"confirmations" : "确认",
"recipient_address" : "收件人地址",
@ -526,4 +529,4 @@
"search": "搜索",
"new_template" : "新模板",
"electrum_address_disclaimer": "每次您使用一个地址时,我们都会生成新地址,但之前的地址仍然有效"
}
}

View file

@ -14,14 +14,14 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_ANDROID_TYPE=$1
MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.0.4"
MONERO_COM_BUILD_NUMBER=11
MONERO_COM_VERSION="1.0.6"
MONERO_COM_BUILD_NUMBER=13
MONERO_COM_BUNDLE_ID="com.monero.app"
MONERO_COM_PACKAGE="com.monero.app"
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.4.0"
CAKEWALLET_BUILD_NUMBER=102
CAKEWALLET_VERSION="4.4.1"
CAKEWALLET_BUILD_NUMBER=104
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
@ -33,6 +33,7 @@ HAVEN_PACKAGE="com.cakewallet.haven"
if ! [[ " ${TYPES[*]} " =~ " ${APP_ANDROID_TYPE} " ]]; then
echo "Wrong app type."
return 1 2>/dev/null
exit 1
fi

View file

@ -11,9 +11,8 @@ ZLIB_DIR=$WORKDIR/zlib
ZLIB_TAG=v1.2.11
ZLIB_COMMIT_HASH="cacf7f1d4e3d44d871b605da3b647f07d718623f"
if [ ! -d "$ZLIB_DIR" ] ; then
git clone -b $ZLIB_TAG --depth 1 https://github.com/madler/zlib $ZLIB_DIR
fi
rm -rf $ZLIB_DIR
git clone -b $ZLIB_TAG --depth 1 https://github.com/madler/zlib $ZLIB_DIR
cd $ZLIB_DIR
git reset --hard $ZLIB_COMMIT_HASH
CC=clang CXX=clang++ ./configure --static

View file

@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_IOS_TYPE=$1
MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.0.4"
MONERO_COM_BUILD_NUMBER=14
MONERO_COM_VERSION="1.0.6"
MONERO_COM_BUILD_NUMBER=16
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.4.0"
CAKEWALLET_BUILD_NUMBER=92
CAKEWALLET_VERSION="4.4.1"
CAKEWALLET_BUILD_NUMBER=100
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
HAVEN_NAME="Haven"

View file

@ -9,6 +9,6 @@ DIR=$(dirname "$0")
case $APP_IOS_TYPE in
"monero.com") $DIR/build_monero_all.sh ;;
"cakewallet") $DIR/build_monero_all.sh ;;
"cakewallet") $DIR/build_monero_all.sh && $DIR/build_haven.sh ;;
"haven") $DIR/build_haven_all.sh ;;
esac

View file

@ -3,7 +3,14 @@
. ./config.sh
cd $EXTERNAL_IOS_LIB_DIR
libtool -static -o libboost.a ./boost/*.a
LIBRANDOMX_PATH=${EXTERNAL_IOS_LIB_DIR}/monero/librandomx.a
if [ -f "$LIBRANDOMX_PATH" ]; then
cp $LIBRANDOMX_PATH ./haven
fi
libtool -static -o libboost.a ./libboost_*.a
libtool -static -o libhaven.a ./haven/*.a
libtool -static -o libmonero.a ./monero/*.a
@ -13,6 +20,7 @@ CW_MONERO_EXTERNAL_LIB=../../../../../cw_monero/ios/External/ios/lib
CW_MONERO_EXTERNAL_INCLUDE=../../../../../cw_monero/ios/External/ios/include
mkdir -p $CW_HAVEN_EXTERNAL_INCLUDE
mkdir -p $CW_MONERO_EXTERNAL_INCLUDE
mkdir -p $CW_HAVEN_EXTERNAL_LIB
mkdir -p $CW_MONERO_EXTERNAL_LIB

View file

@ -15,6 +15,7 @@ Future<void> main(List<String> args) async {
final hasHaven = args.contains('${prefix}haven');
await generateBitcoin(hasBitcoin);
await generateMonero(hasMonero);
await generateHaven(hasHaven);
await generatePubspec(hasMonero: hasMonero, hasBitcoin: hasBitcoin, hasHaven: hasHaven);
await generateWalletTypes(hasMonero: hasMonero, hasBitcoin: hasBitcoin, hasHaven: hasHaven);
}
@ -208,6 +209,8 @@ abstract class Monero {
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex);
String getSubaddressLabel(Object wallet, int accountIndex, int addressIndex);
int getHeigthByDate({DateTime date});
TransactionPriority getDefaultTransactionPriority();
TransactionPriority deserializeMoneroTransactionPriority({int raw});
@ -274,7 +277,8 @@ abstract class MoneroAccountList {
}
Future<void> generateHaven(bool hasImplementation) async {
final outputFile = File(moneroOutputPath);
final outputFile = File(havenOutputPath);
const havenCommonHeaders = """
import 'package:mobx/mobx.dart';
import 'package:flutter/foundation.dart';
@ -287,7 +291,8 @@ import 'package:cw_core/balance.dart';
import 'package:cw_core/output_info.dart';
import 'package:cake_wallet/view_model/send/output.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:hive/hive.dart';""";
import 'package:hive/hive.dart';
import 'package:cw_core/crypto_currency.dart';""";
const havenCWHeaders = """
import 'package:cw_core/get_height_by_date.dart';
import 'package:cw_core/monero_amount_format.dart';
@ -309,6 +314,7 @@ import 'package:cw_haven/mnemonics/portuguese.dart';
import 'package:cw_haven/mnemonics/french.dart';
import 'package:cw_haven/mnemonics/italian.dart';
import 'package:cw_haven/haven_transaction_creation_credentials.dart';
import 'package:cw_haven/api/balance_list.dart';
""";
const havenCwPart = "part 'cw_haven.dart';";
const havenContent = """
@ -353,6 +359,13 @@ class HavenBalance extends Balance {
String get formattedAdditionalBalance => formattedFullBalance;
}
class AssetRate {
final String asset;
final int rate;
AssetRate(this.asset, this.rate);
}
abstract class HavenWalletDetails {
@observable
Account account;
@ -398,6 +411,8 @@ abstract class Haven {
void onStartup();
int getTransactionInfoAccountId(TransactionInfo tx);
WalletService createHavenWalletService(Box<WalletInfo> walletInfoSource);
CryptoCurrency assetOfTransaction(TransactionInfo tx);
List<AssetRate> getAssetRate();
}
abstract class MoneroSubaddressList {
@ -420,8 +435,8 @@ abstract class HavenAccountList {
}
""";
const havenEmptyDefinition = 'Monero monero;\n';
const havenCWDefinition = 'Monero monero = CWMonero();\n';
const havenEmptyDefinition = 'Haven haven;\n';
const havenCWDefinition = 'Haven haven = CWHaven();\n';
final output = '$havenCommonHeaders\n'
+ (hasImplementation ? '$havenCWHeaders\n' : '\n')

View file

@ -23,6 +23,8 @@ class SecretKey {
SecretKey('wyreAccountId', () => ''),
SecretKey('moonPayApiKey', () => ''),
SecretKey('moonPaySecretKey', () => ''),
SecretKey('sideShiftAffiliateId', () => ''),
SecretKey('sideShiftApiKey', () => ''),
];
final String name;