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

This commit is contained in:
fosse 2023-12-19 20:29:42 -05:00
commit c12cd2eada
90 changed files with 9978 additions and 429 deletions

View file

@ -119,6 +119,7 @@ jobs:
cd /opt/android/cake_wallet cd /opt/android/cake_wallet
touch lib/.secrets.g.dart touch lib/.secrets.g.dart
touch cw_ethereum/lib/.secrets.g.dart touch cw_ethereum/lib/.secrets.g.dart
touch cw_polygon/lib/.secrets.g.dart
echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart
echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart
@ -146,13 +147,13 @@ jobs:
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
echo "const robinhoodCIdApiSecret = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart echo "const robinhoodCIdApiSecret = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
- name: Rename app - name: Rename app
run: echo -e "id=com.cakewallet.test\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties run: echo -e "id=com.cakewallet.test\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties

View file

@ -1,6 +1,6 @@
-
uri: polygon-bor.publicnode.com
- -
uri: polygon-rpc.com uri: polygon-rpc.com
-
uri: polygon-bor.publicnode.com
- -
uri: polygon.llamarpc.com uri: polygon.llamarpc.com

View file

@ -1,2 +1,4 @@
Monero Polyseed support, create and restore from a 16 words phrase and without the need to remember the wallet creation date Polyseed enhancements
Bug fixes and enhancements New on-ramp provider DFX
Usability enhancements
Bug fixes

View file

@ -1,3 +1,6 @@
Monero Polyseed support, create and restore from a 16 words phrase and without the need to remember the wallet creation date Add Polygon (Matic) wallet
Add NFTs tab to see all of your purchased NFTs on Ethereum Polyseed enhancements
Bug fixes and enhancements New on-ramp provider DFX
Usability enhancements
Bitcoin enhancements
Bug fixes

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,10 @@ import 'package:cw_bitcoin/bitcoin_amount_format.dart';
import 'package:cw_core/balance.dart'; import 'package:cw_core/balance.dart';
class ElectrumBalance extends Balance { class ElectrumBalance extends Balance {
const ElectrumBalance({required this.confirmed, required this.unconfirmed, required this.frozen}) const ElectrumBalance(
{required this.confirmed,
required this.unconfirmed,
required this.frozen})
: super(confirmed, unconfirmed); : super(confirmed, unconfirmed);
static ElectrumBalance? fromJSON(String? jsonSource) { static ElectrumBalance? fromJSON(String? jsonSource) {
@ -25,16 +28,19 @@ class ElectrumBalance extends Balance {
final int frozen; final int frozen;
@override @override
String get formattedAvailableBalance => bitcoinAmountToString(amount: confirmed - frozen); String get formattedAvailableBalance =>
bitcoinAmountToString(amount: confirmed - unconfirmed.abs() - frozen);
@override @override
String get formattedAdditionalBalance => bitcoinAmountToString(amount: unconfirmed); String get formattedAdditionalBalance =>
bitcoinAmountToString(amount: unconfirmed);
String get formattedFrozenBalance { @override
String get formattedUnAvailableBalance {
final frozenFormatted = bitcoinAmountToString(amount: frozen); final frozenFormatted = bitcoinAmountToString(amount: frozen);
return frozenFormatted == '0.0' ? '' : frozenFormatted; return frozenFormatted == '0.0' ? '' : frozenFormatted;
} }
String toJSON() => String toJSON() => json.encode(
json.encode({'confirmed': confirmed, 'unconfirmed': unconfirmed, 'frozen': frozen}); {'confirmed': confirmed, 'unconfirmed': unconfirmed, 'frozen': frozen});
} }

View file

@ -82,7 +82,7 @@ abstract class ElectrumWalletBase
bitcoin.HDWallet.fromSeed(seedBytes).derivePath("m/44'/145'/0'/0"); bitcoin.HDWallet.fromSeed(seedBytes).derivePath("m/44'/145'/0'/0");
static int estimatedTransactionSize(int inputsCount, int outputsCounts) => static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
inputsCount * 146 + outputsCounts * 33 + 8; inputsCount * 68 + outputsCounts * 34 + 10;
final bitcoin.HDWallet hd; final bitcoin.HDWallet hd;
final String mnemonic; final String mnemonic;

View file

@ -79,11 +79,11 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: cake-update-v3 ref: cake-update-v4
resolved-ref: df9204144011ed9419eff7d9ef3143102a40252d resolved-ref: e19ffb7e7977278a75b27e0479b3c6f4034223b3
url: "https://github.com/cake-tech/bitcoin_flutter.git" url: "https://github.com/cake-tech/bitcoin_flutter.git"
source: git source: git
version: "2.0.2" version: "2.1.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -244,7 +244,7 @@ packages:
source: hosted source: hosted
version: "2.2.4" version: "2.2.4"
encrypt: encrypt:
dependency: "direct main" dependency: transitive
description: description:
name: encrypt name: encrypt
sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb" sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb"
@ -698,15 +698,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.1" version: "1.0.1"
tor:
dependency: transitive
description:
path: "."
ref: main
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
url: "https://github.com/cake-tech/tor.git"
source: git
version: "0.0.1"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:

View file

@ -93,6 +93,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
CryptoCurrency.dydx, CryptoCurrency.dydx,
CryptoCurrency.steth, CryptoCurrency.steth,
CryptoCurrency.banano, CryptoCurrency.banano,
CryptoCurrency.usdtPoly,
CryptoCurrency.usdcEPoly,
]; ];
static const havenCurrencies = [ static const havenCurrencies = [
@ -202,6 +204,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
static const dydx = CryptoCurrency(title: 'DYDX', tag: 'ETH', fullName: 'dYdX', raw: 84, name: 'dydx', iconPath: 'assets/images/dydx_icon.png', decimals: 18); static const dydx = CryptoCurrency(title: 'DYDX', tag: 'ETH', fullName: 'dYdX', raw: 84, name: 'dydx', iconPath: 'assets/images/dydx_icon.png', decimals: 18);
static const steth = CryptoCurrency(title: 'STETH', tag: 'ETH', fullName: 'Lido Staked Ethereum', raw: 85, name: 'steth', iconPath: 'assets/images/steth_icon.png', decimals: 18); static const steth = CryptoCurrency(title: 'STETH', tag: 'ETH', fullName: 'Lido Staked Ethereum', raw: 85, name: 'steth', iconPath: 'assets/images/steth_icon.png', decimals: 18);
static const banano = CryptoCurrency(title: 'BAN', fullName: 'Banano', raw: 86, name: 'banano', iconPath: 'assets/images/nano_icon.png', decimals: 29); static const banano = CryptoCurrency(title: 'BAN', fullName: 'Banano', raw: 86, name: 'banano', iconPath: 'assets/images/nano_icon.png', decimals: 29);
static const usdtPoly = CryptoCurrency(title: 'USDT', tag: 'POLY', fullName: 'Tether USD (PoS)', raw: 87, name: 'usdtpoly', iconPath: 'assets/images/usdt_icon.png', decimals: 6);
static const usdcEPoly = CryptoCurrency(title: 'USDC.E', tag: 'POLY', fullName: 'USD Coin (PoS)', raw: 88, name: 'usdcepoly', iconPath: 'assets/images/usdc_icon.png', decimals: 6);
static final Map<int, CryptoCurrency> _rawCurrencyMap = static final Map<int, CryptoCurrency> _rawCurrencyMap =

View file

@ -18,6 +18,8 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
bool _enabled; bool _enabled;
@HiveField(5) @HiveField(5)
final String? iconPath; final String? iconPath;
@HiveField(6)
final String? tag;
bool get enabled => _enabled; bool get enabled => _enabled;
@ -30,30 +32,31 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
required this.decimal, required this.decimal,
bool enabled = true, bool enabled = true,
this.iconPath, this.iconPath,
this.tag,
}) : _enabled = enabled, }) : _enabled = enabled,
super( super(
name: symbol.toLowerCase(), name: symbol.toLowerCase(),
title: symbol.toUpperCase(), title: symbol.toUpperCase(),
fullName: name, fullName: name,
tag: "ETH", tag: tag,
iconPath: iconPath, iconPath: iconPath,
decimals: decimal decimals: decimal);
);
Erc20Token.copyWith(Erc20Token other, String? icon) Erc20Token.copyWith(Erc20Token other, String? icon, String? tag)
: this.name = other.name, : this.name = other.name,
this.symbol = other.symbol, this.symbol = other.symbol,
this.contractAddress = other.contractAddress, this.contractAddress = other.contractAddress,
this.decimal = other.decimal, this.decimal = other.decimal,
this._enabled = other.enabled, this._enabled = other.enabled,
this.tag = tag,
this.iconPath = icon, this.iconPath = icon,
super( super(
name: other.name, name: other.name,
title: other.symbol.toUpperCase(), title: other.symbol.toUpperCase(),
fullName: other.name, fullName: other.name,
tag: "ETH", tag: tag,
iconPath: icon, iconPath: icon,
decimals: other.decimal decimals: other.decimal,
); );
static const typeId = ERC20_TOKEN_TYPE_ID; static const typeId = ERC20_TOKEN_TYPE_ID;
@ -61,7 +64,8 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
static const polygonBoxName = ' PolygonErc20Tokens'; static const polygonBoxName = ' PolygonErc20Tokens';
@override @override
bool operator ==(other) => (other is Erc20Token && other.contractAddress == contractAddress) || bool operator ==(other) =>
(other is Erc20Token && other.contractAddress == contractAddress) ||
(other is CryptoCurrency && other.title == title); (other is CryptoCurrency && other.title == title);
@override @override

View file

@ -214,7 +214,7 @@ class Node extends HiveObject with Keyable {
} }
Future<bool> requestNodeWithProxy() async { Future<bool> requestNodeWithProxy() async {
if (!isValidProxyAddress/* && !Tor.instance.enabled*/) { if (!isValidProxyAddress /* && !Tor.instance.enabled*/) {
return false; return false;
} }

View file

@ -616,15 +616,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.1" version: "1.0.1"
tor:
dependency: "direct main"
description:
path: "."
ref: main
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
url: "https://github.com/cake-tech/tor.git"
source: git
version: "0.0.1"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:

View file

@ -293,17 +293,13 @@ class DefaultErc20Tokens {
]; ];
List<Erc20Token> get initialErc20Tokens => _defaultTokens.map((token) { List<Erc20Token> get initialErc20Tokens => _defaultTokens.map((token) {
String? iconPath; String? iconPath;
try { try {
iconPath = CryptoCurrency.all iconPath = CryptoCurrency.all
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase()) .firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
.iconPath; .iconPath;
} catch (_) {} } catch (_) {}
if (iconPath != null) { return Erc20Token.copyWith(token, iconPath, 'ETH');
return Erc20Token.copyWith(token, iconPath); }).toList();
}
return token;
}).toList();
} }

View file

@ -78,19 +78,18 @@ class EthereumClient {
currency == CryptoCurrency.maticpoly || currency == CryptoCurrency.maticpoly ||
contractAddress != null); contractAddress != null);
bool _isEVMCompatibleChain = currency == CryptoCurrency.eth || currency == CryptoCurrency.maticpoly; bool _isEVMCompatibleChain =
currency == CryptoCurrency.eth || currency == CryptoCurrency.maticpoly;
final price = _client!.getGasPrice(); final price = _client!.getGasPrice();
final Transaction transaction = Transaction( final Transaction transaction = createTransaction(
from: privateKey.address, from: privateKey.address,
to: EthereumAddress.fromHex(toAddress), to: EthereumAddress.fromHex(toAddress),
maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip), maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip),
value: _isEVMCompatibleChain ? EtherAmount.inWei(BigInt.parse(amount)) : EtherAmount.zero(), amount: _isEVMCompatibleChain ? EtherAmount.inWei(BigInt.parse(amount)) : EtherAmount.zero(),
); );
final chainId = _getChainIdForCurrency(currency);
final signedTransaction = final signedTransaction =
await _client!.signTransaction(privateKey, transaction, chainId: chainId); await _client!.signTransaction(privateKey, transaction, chainId: chainId);
@ -124,18 +123,27 @@ class EthereumClient {
); );
} }
int _getChainIdForCurrency(CryptoCurrency currency) { int get chainId => 1;
switch (currency) {
case CryptoCurrency.maticpoly: Transaction createTransaction({
return 137; required EthereumAddress from,
case CryptoCurrency.eth: required EthereumAddress to,
default: required EtherAmount amount,
return 1; EtherAmount? maxPriorityFeePerGas,
} }) {
return Transaction(
from: from,
to: to,
maxPriorityFeePerGas: maxPriorityFeePerGas,
value: amount,
);
} }
Future<String> sendTransaction(Uint8List signedTransaction) async => Future<String> sendTransaction(Uint8List signedTransaction) async =>
await _client!.sendRawTransaction(prependTransactionType(0x02, signedTransaction)); await _client!.sendRawTransaction(prepareSignedTransactionForSending(signedTransaction));
Uint8List prepareSignedTransactionForSending(Uint8List signedTransaction) =>
prependTransactionType(0x02, signedTransaction);
Future getTransactionDetails(String transactionHash) async { Future getTransactionDetails(String transactionHash) async {
// Wait for the transaction receipt to become available // Wait for the transaction receipt to become available

View file

@ -14,7 +14,7 @@ import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_ethereum/default_erc20_tokens.dart'; import 'package:cw_ethereum/default_ethereum_erc20_tokens.dart';
import 'package:cw_ethereum/erc20_balance.dart'; import 'package:cw_ethereum/erc20_balance.dart';
import 'package:cw_ethereum/ethereum_client.dart'; import 'package:cw_ethereum/ethereum_client.dart';
import 'package:cw_ethereum/ethereum_exceptions.dart'; import 'package:cw_ethereum/ethereum_exceptions.dart';
@ -429,6 +429,7 @@ abstract class EthereumWalletBase
contractAddress: token.contractAddress, contractAddress: token.contractAddress,
decimal: token.decimal, decimal: token.decimal,
enabled: token.enabled, enabled: token.enabled,
tag: token.tag ?? "ETH",
iconPath: iconPath, iconPath: iconPath,
); );
@ -492,7 +493,7 @@ abstract class EthereumWalletBase
_transactionsUpdateTimer!.cancel(); _transactionsUpdateTimer!.cancel();
} }
_transactionsUpdateTimer = Timer.periodic(Duration(seconds: 10), (_) { _transactionsUpdateTimer = Timer.periodic(const Duration(seconds: 10), (_) {
_updateTransactions(); _updateTransactions();
_updateBalance(); _updateBalance();
}); });
@ -508,7 +509,7 @@ abstract class EthereumWalletBase
} }
@override @override
String signMessage(String message, {String? address = null}) => String signMessage(String message, {String? address}) =>
bytesToHex(_ethPrivateKey.signPersonalMessageToUint8List(ascii.encode(message))); bytesToHex(_ethPrivateKey.signPersonalMessageToUint8List(ascii.encode(message)));
Web3Client? getWeb3Client() => _client.getWeb3Client(); Web3Client? getWeb3Client() => _client.getWeb3Client();

View file

@ -153,6 +153,22 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
hashlib:
dependency: transitive
description:
name: hashlib
sha256: "71bf102329ddb8e50c8a995ee4645ae7f1728bb65e575c17196b4d8262121a96"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
hashlib_codecs:
dependency: transitive
description:
name: hashlib_codecs
sha256: "49e2a471f74b15f1854263e58c2ac11f2b631b5b12c836f9708a35397d36d626"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
http: http:
dependency: transitive dependency: transitive
description: description:
@ -308,12 +324,11 @@ packages:
polyseed: polyseed:
dependency: transitive dependency: transitive
description: description:
path: "." name: polyseed
ref: HEAD sha256: "9b48ec535b10863f78f6354ec983b4cc0c88ca69ff48fee469d0fd1954b01d4f"
resolved-ref: "504d58a5b147fccd3bc85a25f2e72fb32771ddd7" url: "https://pub.dev"
url: "https://github.com/cake-tech/polyseed_dart.git" source: hosted
source: git version: "0.0.2"
version: "0.0.1"
process: process:
dependency: transitive dependency: transitive
description: description:
@ -383,15 +398,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.1" version: "0.5.1"
tor:
dependency: transitive
description:
path: "."
ref: main
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
url: "https://github.com/cake-tech/tor.git"
source: git
version: "0.0.1"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:

View file

@ -29,7 +29,7 @@ class DefaultPolygonErc20Tokens {
symbol: "USDC.e", symbol: "USDC.e",
contractAddress: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", contractAddress: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
decimal: 6, decimal: 6,
enabled: false, enabled: true,
), ),
Erc20Token( Erc20Token(
name: "Avalanche Token", name: "Avalanche Token",
@ -73,14 +73,10 @@ class DefaultPolygonErc20Tokens {
try { try {
iconPath = CryptoCurrency.all iconPath = CryptoCurrency.all
.firstWhere((element) => .firstWhere((element) =>
element.title.toUpperCase() == token.symbol.toUpperCase()) element.title.toUpperCase() == token.symbol.split(".").first.toUpperCase())
.iconPath; .iconPath;
} catch (_) {} } catch (_) {}
if (iconPath != null) { return Erc20Token.copyWith(token, iconPath, 'POLY');
return Erc20Token.copyWith(token, iconPath);
}
return token;
}).toList(); }).toList();
} }

View file

@ -3,8 +3,30 @@ import 'dart:convert';
import 'package:cw_ethereum/ethereum_client.dart'; import 'package:cw_ethereum/ethereum_client.dart';
import 'package:cw_polygon/polygon_transaction_model.dart'; import 'package:cw_polygon/polygon_transaction_model.dart';
import 'package:cw_ethereum/.secrets.g.dart' as secrets; import 'package:cw_ethereum/.secrets.g.dart' as secrets;
import 'package:flutter/foundation.dart';
import 'package:web3dart/web3dart.dart';
class PolygonClient extends EthereumClient { class PolygonClient extends EthereumClient {
@override
Transaction createTransaction({
required EthereumAddress from,
required EthereumAddress to,
required EtherAmount amount,
EtherAmount? maxPriorityFeePerGas,
}) {
return Transaction(
from: from,
to: to,
value: amount,
);
}
@override
Uint8List prepareSignedTransactionForSending(Uint8List signedTransaction) => signedTransaction;
@override
int get chainId => 137;
@override @override
Future<List<PolygonTransactionModel>> fetchTransactions(String address, Future<List<PolygonTransactionModel>> fetchTransactions(String address,
{String? contractAddress}) async { {String? contractAddress}) async {
@ -27,7 +49,6 @@ class PolygonClient extends EthereumClient {
return []; return [];
} catch (e) { } catch (e) {
print(e);
return []; return [];
} }
} }

View file

@ -16,10 +16,9 @@ import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_ethereum/erc20_balance.dart'; import 'package:cw_ethereum/erc20_balance.dart';
import 'package:cw_ethereum/ethereum_formatter.dart'; import 'package:cw_ethereum/ethereum_formatter.dart';
import 'package:cw_ethereum/ethereum_transaction_model.dart';
import 'package:cw_ethereum/file.dart'; import 'package:cw_ethereum/file.dart';
import 'package:cw_core/erc20_token.dart'; import 'package:cw_core/erc20_token.dart';
import 'package:cw_polygon/default_erc20_tokens.dart'; import 'package:cw_polygon/default_polygon_erc20_tokens.dart';
import 'package:cw_polygon/polygon_client.dart'; import 'package:cw_polygon/polygon_client.dart';
import 'package:cw_polygon/polygon_exceptions.dart'; import 'package:cw_polygon/polygon_exceptions.dart';
import 'package:cw_polygon/polygon_formatter.dart'; import 'package:cw_polygon/polygon_formatter.dart';
@ -42,28 +41,26 @@ part 'polygon_wallet.g.dart';
class PolygonWallet = PolygonWalletBase with _$PolygonWallet; class PolygonWallet = PolygonWalletBase with _$PolygonWallet;
abstract class PolygonWalletBase extends WalletBase<ERC20Balance, abstract class PolygonWalletBase
PolygonTransactionHistory, PolygonTransactionInfo> with Store { extends WalletBase<ERC20Balance, PolygonTransactionHistory, PolygonTransactionInfo> with Store {
PolygonWalletBase({ PolygonWalletBase({
required WalletInfo walletInfo, required WalletInfo walletInfo,
String? mnemonic, String? mnemonic,
String? privateKey, String? privateKey,
required String password, required String password,
ERC20Balance? initialBalance, ERC20Balance? initialBalance,
}) : syncStatus = NotConnectedSyncStatus(), }) : syncStatus = const NotConnectedSyncStatus(),
_password = password, _password = password,
_mnemonic = mnemonic, _mnemonic = mnemonic,
_hexPrivateKey = privateKey, _hexPrivateKey = privateKey,
_isTransactionUpdating = false, _isTransactionUpdating = false,
_client = PolygonClient(), _client = PolygonClient(),
walletAddresses = PolygonWalletAddresses(walletInfo), walletAddresses = PolygonWalletAddresses(walletInfo),
balance = ObservableMap<CryptoCurrency, ERC20Balance>.of({ balance = ObservableMap<CryptoCurrency, ERC20Balance>.of(
CryptoCurrency.maticpoly: initialBalance ?? ERC20Balance(BigInt.zero) {CryptoCurrency.maticpoly: initialBalance ?? ERC20Balance(BigInt.zero)}),
}),
super(walletInfo) { super(walletInfo) {
this.walletInfo = walletInfo; this.walletInfo = walletInfo;
transactionHistory = transactionHistory = PolygonTransactionHistory(walletInfo: walletInfo, password: password);
PolygonTransactionHistory(walletInfo: walletInfo, password: password);
if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) { if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
CakeHive.registerAdapter(Erc20TokenAdapter()); CakeHive.registerAdapter(Erc20TokenAdapter());
@ -80,9 +77,9 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
late final EthPrivateKey _polygonPrivateKey; late final EthPrivateKey _polygonPrivateKey;
EthPrivateKey get polygonPrivateKey => _polygonPrivateKey; late final PolygonClient _client;
late PolygonClient _client; EthPrivateKey get polygonPrivateKey => _polygonPrivateKey;
int? _gasPrice; int? _gasPrice;
int? _estimatedGas; int? _estimatedGas;
@ -102,11 +99,11 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
@observable @observable
late ObservableMap<CryptoCurrency, ERC20Balance> balance; late ObservableMap<CryptoCurrency, ERC20Balance> balance;
Completer<SharedPreferences> _sharedPrefs = Completer(); final Completer<SharedPreferences> _sharedPrefs = Completer();
Future<void> init() async { Future<void> init() async {
polygonErc20TokensBox = polygonErc20TokensBox = await CakeHive.openBox<Erc20Token>(
await CakeHive.openBox<Erc20Token>(Erc20Token.polygonBoxName); "${walletInfo.name.replaceAll(" ", "_")}_${Erc20Token.polygonBoxName}");
await walletAddresses.init(); await walletAddresses.init();
await transactionHistory.init(); await transactionHistory.init();
_polygonPrivateKey = await getPrivateKey( _polygonPrivateKey = await getPrivateKey(
@ -122,8 +119,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
int calculateEstimatedFee(TransactionPriority priority, int? amount) { int calculateEstimatedFee(TransactionPriority priority, int? amount) {
try { try {
if (priority is PolygonTransactionPriority) { if (priority is PolygonTransactionPriority) {
final priorityFee = final priorityFee = EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
return (_gasPrice! + priorityFee) * (_estimatedGas ?? 0); return (_gasPrice! + priorityFee) * (_estimatedGas ?? 0);
} }
@ -168,33 +164,29 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
@override @override
Future<PendingTransaction> createTransaction(Object credentials) async { Future<PendingTransaction> createTransaction(Object credentials) async {
final _credentials = credentials as PolygonTransactionCredentials; final credentials0 = credentials as PolygonTransactionCredentials;
final outputs = _credentials.outputs; final outputs = credentials0.outputs;
final hasMultiDestination = outputs.length > 1; final hasMultiDestination = outputs.length > 1;
final CryptoCurrency transactionCurrency = balance.keys final CryptoCurrency transactionCurrency =
.firstWhere((element) => element.title == _credentials.currency.title); balance.keys.firstWhere((element) => element.title == credentials0.currency.title);
final _erc20Balance = balance[transactionCurrency]!; final erc20Balance = balance[transactionCurrency]!;
BigInt totalAmount = BigInt.zero; BigInt totalAmount = BigInt.zero;
int exponent = int exponent = transactionCurrency is Erc20Token ? transactionCurrency.decimal : 18;
transactionCurrency is Erc20Token ? transactionCurrency.decimal : 18;
num amountToPolygonMultiplier = pow(10, exponent); num amountToPolygonMultiplier = pow(10, exponent);
// so far this can not be made with Polygon as Polygon does not support multiple recipients // so far this can not be made with Polygon as Polygon does not support multiple recipients
if (hasMultiDestination) { if (hasMultiDestination) {
if (outputs.any( if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
(item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
throw PolygonTransactionCreationException(transactionCurrency); throw PolygonTransactionCreationException(transactionCurrency);
} }
final totalOriginalAmount = PolygonFormatter.parsePolygonAmountToDouble( final totalOriginalAmount = PolygonFormatter.parsePolygonAmountToDouble(
outputs.fold( outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)));
0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0))); totalAmount = BigInt.from(totalOriginalAmount * amountToPolygonMultiplier);
totalAmount =
BigInt.from(totalOriginalAmount * amountToPolygonMultiplier);
if (_erc20Balance.balance < totalAmount) { if (erc20Balance.balance < totalAmount) {
throw PolygonTransactionCreationException(transactionCurrency); throw PolygonTransactionCreationException(transactionCurrency);
} }
} else { } else {
@ -203,35 +195,33 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
// then no need to subtract the fees from the amount if send all // then no need to subtract the fees from the amount if send all
final BigInt allAmount; final BigInt allAmount;
if (transactionCurrency is Erc20Token) { if (transactionCurrency is Erc20Token) {
allAmount = _erc20Balance.balance; allAmount = erc20Balance.balance;
} else { } else {
allAmount = _erc20Balance.balance - allAmount =
BigInt.from(calculateEstimatedFee(_credentials.priority!, null)); erc20Balance.balance - BigInt.from(calculateEstimatedFee(credentials0.priority!, null));
} }
final totalOriginalAmount = EthereumFormatter.parseEthereumAmountToDouble( final totalOriginalAmount =
output.formattedCryptoAmount ?? 0); EthereumFormatter.parseEthereumAmountToDouble(output.formattedCryptoAmount ?? 0);
totalAmount = output.sendAll totalAmount =
? allAmount output.sendAll ? allAmount : BigInt.from(totalOriginalAmount * amountToPolygonMultiplier);
: BigInt.from(totalOriginalAmount * amountToPolygonMultiplier);
if (_erc20Balance.balance < totalAmount) { if (erc20Balance.balance < totalAmount) {
throw PolygonTransactionCreationException(transactionCurrency); throw PolygonTransactionCreationException(transactionCurrency);
} }
} }
final pendingPolygonTransaction = await _client.signTransaction( final pendingPolygonTransaction = await _client.signTransaction(
privateKey: _polygonPrivateKey, privateKey: _polygonPrivateKey,
toAddress: _credentials.outputs.first.isParsedAddress toAddress: credentials0.outputs.first.isParsedAddress
? _credentials.outputs.first.extractedAddress! ? credentials0.outputs.first.extractedAddress!
: _credentials.outputs.first.address, : credentials0.outputs.first.address,
amount: totalAmount.toString(), amount: totalAmount.toString(),
gas: _estimatedGas!, gas: _estimatedGas!,
priority: _credentials.priority!, priority: credentials0.priority!,
currency: transactionCurrency, currency: transactionCurrency,
exponent: exponent, exponent: exponent,
contractAddress: transactionCurrency is Erc20Token contractAddress:
? transactionCurrency.contractAddress transactionCurrency is Erc20Token ? transactionCurrency.contractAddress : null,
: null,
); );
return pendingPolygonTransaction; return pendingPolygonTransaction;
@ -262,15 +252,16 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
final address = _polygonPrivateKey.address.hex; final address = _polygonPrivateKey.address.hex;
final transactions = await _client.fetchTransactions(address); final transactions = await _client.fetchTransactions(address);
final List<Future<List<PolygonTransactionModel>>> polygonErc20TokensTransactions = final List<Future<List<PolygonTransactionModel>>> polygonErc20TokensTransactions = [];
[];
for (var token in balance.keys) { for (var token in balance.keys) {
if (token is Erc20Token) { if (token is Erc20Token) {
polygonErc20TokensTransactions.add(_client.fetchTransactions( polygonErc20TokensTransactions.add(
address, _client.fetchTransactions(
contractAddress: token.contractAddress, address,
) as Future<List<PolygonTransactionModel>>); contractAddress: token.contractAddress,
),
);
} }
} }
@ -294,8 +285,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
isPending: false, isPending: false,
date: transactionModel.date, date: transactionModel.date,
confirmations: transactionModel.confirmations, confirmations: transactionModel.confirmations,
ethFee: ethFee: BigInt.from(transactionModel.gasUsed) * transactionModel.gasPrice,
BigInt.from(transactionModel.gasUsed) * transactionModel.gasPrice,
exponent: transactionModel.tokenDecimal ?? 18, exponent: transactionModel.tokenDecimal ?? 18,
tokenSymbol: transactionModel.tokenSymbol ?? "MATIC", tokenSymbol: transactionModel.tokenSymbol ?? "MATIC",
to: transactionModel.to, to: transactionModel.to,
@ -337,8 +327,8 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
_gasPrice = await _client.getGasUnitPrice(); _gasPrice = await _client.getGasUnitPrice();
_estimatedGas = await _client.getEstimatedGas(); _estimatedGas = await _client.getEstimatedGas();
Timer.periodic(const Duration(minutes: 1), Timer.periodic(
(timer) async => _gasPrice = await _client.getGasUnitPrice()); const Duration(minutes: 1), (timer) async => _gasPrice = await _client.getGasUnitPrice());
Timer.periodic(const Duration(seconds: 10), Timer.periodic(const Duration(seconds: 10),
(timer) async => _estimatedGas = await _client.getEstimatedGas()); (timer) async => _estimatedGas = await _client.getEstimatedGas());
@ -348,8 +338,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
} }
} }
Future<String> makePath() async => Future<String> makePath() async => pathForWallet(name: walletInfo.name, type: walletInfo.type);
pathForWallet(name: walletInfo.name, type: walletInfo.type);
String toJSON() => json.encode({ String toJSON() => json.encode({
'mnemonic': _mnemonic, 'mnemonic': _mnemonic,
@ -367,8 +356,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
final data = json.decode(jsonSource) as Map; final data = json.decode(jsonSource) as Map;
final mnemonic = data['mnemonic'] as String?; final mnemonic = data['mnemonic'] as String?;
final privateKey = data['private_key'] as String?; final privateKey = data['private_key'] as String?;
final balance = ERC20Balance.fromJSON(data['balance'] as String) ?? final balance = ERC20Balance.fromJSON(data['balance'] as String) ?? ERC20Balance(BigInt.zero);
ERC20Balance(BigInt.zero);
return PolygonWallet( return PolygonWallet(
walletInfo: walletInfo, walletInfo: walletInfo,
@ -418,14 +406,14 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
final root = bip32.BIP32.fromSeed(seed); final root = bip32.BIP32.fromSeed(seed);
const _hdPathPolygon = "m/44'/60'/0'/0"; const hdPathPolygon = "m/44'/60'/0'/0";
const index = 0; const index = 0;
final addressAtIndex = root.derivePath("$_hdPathPolygon/$index"); final addressAtIndex = root.derivePath("$hdPathPolygon/$index");
return EthPrivateKey.fromHex( return EthPrivateKey.fromHex(HEX.encode(addressAtIndex.privateKey as List<int>));
HEX.encode(addressAtIndex.privateKey as List<int>));
} }
@override
Future<void>? updateBalance() async => await _updateBalance(); Future<void>? updateBalance() async => await _updateBalance();
List<Erc20Token> get erc20Currencies => polygonErc20TokensBox.values.toList(); List<Erc20Token> get erc20Currencies => polygonErc20TokensBox.values.toList();
@ -434,29 +422,29 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
String? iconPath; String? iconPath;
try { try {
iconPath = CryptoCurrency.all iconPath = CryptoCurrency.all
.firstWhere((element) => .firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
element.title.toUpperCase() == token.symbol.toUpperCase())
.iconPath; .iconPath;
} catch (_) {} } catch (_) {}
final _token = Erc20Token( final token0 = Erc20Token(
name: token.name, name: token.name,
symbol: token.symbol, symbol: token.symbol,
contractAddress: token.contractAddress, contractAddress: token.contractAddress,
decimal: token.decimal, decimal: token.decimal,
enabled: token.enabled, enabled: token.enabled,
tag: token.tag ?? "POLY",
iconPath: iconPath, iconPath: iconPath,
); );
await polygonErc20TokensBox.put(_token.contractAddress, _token); await polygonErc20TokensBox.put(token0.contractAddress, token0);
if (_token.enabled) { if (token0.enabled) {
balance[_token] = await _client.fetchERC20Balances( balance[token0] = await _client.fetchERC20Balances(
_polygonPrivateKey.address, _polygonPrivateKey.address,
_token.contractAddress, token0.contractAddress,
); );
} else { } else {
balance.remove(_token); balance.remove(token0);
} }
} }
@ -476,8 +464,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
} }
void addInitialTokens() { void addInitialTokens() {
final initialErc20Tokens = final initialErc20Tokens = DefaultPolygonErc20Tokens().initialPolygonErc20Tokens;
DefaultPolygonErc20Tokens().initialPolygonErc20Tokens;
for (var token in initialErc20Tokens) { for (var token in initialErc20Tokens) {
polygonErc20TokensBox.put(token.contractAddress, token); polygonErc20TokensBox.put(token.contractAddress, token);
@ -486,26 +473,20 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
@override @override
Future<void> renameWalletFiles(String newWalletName) async { Future<void> renameWalletFiles(String newWalletName) async {
final currentWalletPath = final currentWalletPath = await pathForWallet(name: walletInfo.name, type: type);
await pathForWallet(name: walletInfo.name, type: type);
final currentWalletFile = File(currentWalletPath); final currentWalletFile = File(currentWalletPath);
final currentDirPath = final currentDirPath = await pathForWalletDir(name: walletInfo.name, type: type);
await pathForWalletDir(name: walletInfo.name, type: type); final currentTransactionsFile = File('$currentDirPath/$transactionsHistoryFileName');
final currentTransactionsFile =
File('$currentDirPath/$transactionsHistoryFileName');
// Copies current wallet files into new wallet name's dir and files // Copies current wallet files into new wallet name's dir and files
if (currentWalletFile.existsSync()) { if (currentWalletFile.existsSync()) {
final newWalletPath = final newWalletPath = await pathForWallet(name: newWalletName, type: type);
await pathForWallet(name: newWalletName, type: type);
await currentWalletFile.copy(newWalletPath); await currentWalletFile.copy(newWalletPath);
} }
if (currentTransactionsFile.existsSync()) { if (currentTransactionsFile.existsSync()) {
final newDirPath = final newDirPath = await pathForWalletDir(name: newWalletName, type: type);
await pathForWalletDir(name: newWalletName, type: type); await currentTransactionsFile.copy('$newDirPath/$transactionsHistoryFileName');
await currentTransactionsFile
.copy('$newDirPath/$transactionsHistoryFileName');
} }
// Delete old name's dir and files // Delete old name's dir and files
@ -517,7 +498,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
_transactionsUpdateTimer!.cancel(); _transactionsUpdateTimer!.cancel();
} }
_transactionsUpdateTimer = Timer.periodic(Duration(seconds: 10), (_) { _transactionsUpdateTimer = Timer.periodic(const Duration(seconds: 10), (_) {
_updateTransactions(); _updateTransactions();
_updateBalance(); _updateBalance();
}); });
@ -533,8 +514,8 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
} }
@override @override
String signMessage(String message, {String? address = null}) => bytesToHex( String signMessage(String message, {String? address}) =>
_polygonPrivateKey.signPersonalMessageToUint8List(ascii.encode(message))); bytesToHex(_polygonPrivateKey.signPersonalMessageToUint8List(ascii.encode(message)));
Web3Client? getWeb3Client() => _client.getWeb3Client(); Web3Client? getWeb3Client() => _client.getWeb3Client();
} }

View file

@ -122,6 +122,8 @@ PODS:
- Flutter - Flutter
- MTBBarcodeScanner (5.0.11) - MTBBarcodeScanner (5.0.11)
- OrderedSet (5.0.0) - OrderedSet (5.0.0)
- package_info (0.0.1):
- Flutter
- package_info_plus (0.4.5): - package_info_plus (0.4.5):
- Flutter - Flutter
- path_provider_foundation (0.0.1): - path_provider_foundation (0.0.1):
@ -143,8 +145,6 @@ PODS:
- SwiftProtobuf (1.22.0) - SwiftProtobuf (1.22.0)
- SwiftyGif (5.4.4) - SwiftyGif (5.4.4)
- Toast (4.0.0) - Toast (4.0.0)
- tor (0.0.1):
- Flutter
- uni_links (0.0.1): - uni_links (0.0.1):
- Flutter - Flutter
- UnstoppableDomainsResolution (4.0.0): - UnstoppableDomainsResolution (4.0.0):
@ -175,13 +175,13 @@ DEPENDENCIES:
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- in_app_review (from `.symlinks/plugins/in_app_review/ios`) - in_app_review (from `.symlinks/plugins/in_app_review/ios`)
- local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`) - local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`)
- package_info (from `.symlinks/plugins/package_info/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`) - sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- tor (from `.symlinks/plugins/tor/ios`)
- uni_links (from `.symlinks/plugins/uni_links/ios`) - uni_links (from `.symlinks/plugins/uni_links/ios`)
- UnstoppableDomainsResolution (~> 4.0.0) - UnstoppableDomainsResolution (~> 4.0.0)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
@ -236,6 +236,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/in_app_review/ios" :path: ".symlinks/plugins/in_app_review/ios"
local_auth_ios: local_auth_ios:
:path: ".symlinks/plugins/local_auth_ios/ios" :path: ".symlinks/plugins/local_auth_ios/ios"
package_info:
:path: ".symlinks/plugins/package_info/ios"
package_info_plus: package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios" :path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation: path_provider_foundation:
@ -248,8 +250,6 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/share_plus/ios" :path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation: shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin" :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
tor:
:path: ".symlinks/plugins/tor/ios"
uni_links: uni_links:
:path: ".symlinks/plugins/uni_links/ios" :path: ".symlinks/plugins/uni_links/ios"
url_launcher_ios: url_launcher_ios:
@ -282,6 +282,7 @@ SPEC CHECKSUMS:
local_auth_ios: c6cf091ded637a88f24f86a8875d8b0f526e2605 local_auth_ios: c6cf091ded637a88f24f86a8875d8b0f526e2605
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
@ -293,7 +294,6 @@ SPEC CHECKSUMS:
SwiftProtobuf: 40bd808372cb8706108f22d28f8ab4a6b9bc6989 SwiftProtobuf: 40bd808372cb8706108f22d28f8ab4a6b9bc6989
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
tor: 662a9f5b980b5c86decb8ba611de9bcd4c8286eb
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841 UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841
url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b

View file

@ -32,6 +32,8 @@ class AddressValidator extends TextValidator {
return '[0-9a-zA-Z_]'; return '[0-9a-zA-Z_]';
case CryptoCurrency.usdc: case CryptoCurrency.usdc:
case CryptoCurrency.usdcpoly: case CryptoCurrency.usdcpoly:
case CryptoCurrency.usdtPoly:
case CryptoCurrency.usdcEPoly:
case CryptoCurrency.ape: case CryptoCurrency.ape:
case CryptoCurrency.avaxc: case CryptoCurrency.avaxc:
case CryptoCurrency.eth: case CryptoCurrency.eth:
@ -141,6 +143,8 @@ class AddressValidator extends TextValidator {
return [42]; return [42];
case CryptoCurrency.eth: case CryptoCurrency.eth:
case CryptoCurrency.usdcpoly: case CryptoCurrency.usdcpoly:
case CryptoCurrency.usdtPoly:
case CryptoCurrency.usdcEPoly:
case CryptoCurrency.mana: case CryptoCurrency.mana:
case CryptoCurrency.matic: case CryptoCurrency.matic:
case CryptoCurrency.maticpoly: case CryptoCurrency.maticpoly:

View file

@ -285,10 +285,12 @@ class EvmChainServiceImpl implements ChainService {
} }
String _convertToReadable(Map<String, dynamic> data) { String _convertToReadable(Map<String, dynamic> data) {
final tokenName = getTokenNameBasedOnWalletType(appStore.wallet!.type);
String gas = int.parse((data['gas'] as String).substring(2), radix: 16).toString(); String gas = int.parse((data['gas'] as String).substring(2), radix: 16).toString();
String value = data['value'] != null String value = data['value'] != null
? (int.parse((data['value'] as String).substring(2), radix: 16) / 1e18).toString() + ' ETH' ? (int.parse((data['value'] as String).substring(2), radix: 16) / 1e18).toString() +
: '0 ETH'; ' $tokenName'
: '0 $tokenName';
String from = data['from'] as String; String from = data['from'] as String;
String to = data['to'] as String; String to = data['to'] as String;

View file

@ -19,7 +19,6 @@ import 'package:cake_wallet/ionia/ionia_anypay.dart';
import 'package:cake_wallet/ionia/ionia_gift_card.dart'; import 'package:cake_wallet/ionia/ionia_gift_card.dart';
import 'package:cake_wallet/ionia/ionia_tip.dart'; import 'package:cake_wallet/ionia/ionia_tip.dart';
import 'package:cake_wallet/polygon/polygon.dart'; import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart'; import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
import 'package:cake_wallet/src/screens/buy/buy_options_page.dart'; import 'package:cake_wallet/src/screens/buy/buy_options_page.dart';
@ -382,7 +381,8 @@ Future<void> setup({
settingsStore: settingsStore, settingsStore: settingsStore,
yatStore: getIt.get<YatStore>(), yatStore: getIt.get<YatStore>(),
ordersStore: getIt.get<OrdersStore>(), ordersStore: getIt.get<OrdersStore>(),
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>())); anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>(),
keyService: getIt.get<KeyService>()));
getIt.registerFactory<AuthService>( getIt.registerFactory<AuthService>(
() => AuthService( () => AuthService(
@ -761,13 +761,7 @@ Future<void> setup({
return PowNodeListViewModel(_powNodeSource, appStore); return PowNodeListViewModel(_powNodeSource, appStore);
}); });
getIt.registerFactory(() { getIt.registerFactory(() => ConnectionSyncPage(getIt.get<DashboardViewModel>()));
final wallet = getIt.get<AppStore>().wallet;
return ConnectionSyncPage(
getIt.get<DashboardViewModel>(),
isEVMCompatibleChain(wallet!.type) ? getIt.get<Web3WalletService>() : null,
);
});
getIt.registerFactory( getIt.registerFactory(
() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(), getIt.get<AuthService>())); () => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(), getIt.get<AuthService>()));

View file

@ -1,6 +1,5 @@
import 'dart:io' show Directory, File, Platform; import 'dart:io' show Directory, File, Platform;
import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/entities/encrypt.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pathForWallet.dart';
import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cake_wallet/entities/secret_store_key.dart';
@ -186,7 +185,6 @@ Future<void> defaultSettingsMigration(
case 25: case 25:
await rewriteSecureStoragePin(secureStorage: secureStorage); await rewriteSecureStoragePin(secureStorage: secureStorage);
break; break;
default: default:
break; break;
} }

View file

@ -0,0 +1,34 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cw_core/enumerable_item.dart';
class ListOrderMode extends EnumerableItem<int> with Serializable<int> {
const ListOrderMode({required String title, required int raw}) : super(title: title, raw: raw);
static const all = [ListOrderMode.ascending, ListOrderMode.descending];
static const ascending = ListOrderMode(raw: 0, title: 'Ascending');
static const descending = ListOrderMode(raw: 1, title: 'Descending');
static ListOrderMode deserialize({required int raw}) {
switch (raw) {
case 0:
return ascending;
case 1:
return descending;
default:
throw Exception('Unexpected token: $raw for ListOrderMode deserialize');
}
}
@override
String toString() {
switch (this) {
case ListOrderMode.ascending:
return S.current.ascending;
case ListOrderMode.descending:
return S.current.descending;
default:
return '';
}
}
}

View file

@ -85,8 +85,7 @@ Future<List<Node>> loadDefaultEthereumNodes() async {
} }
Future<List<Node>> loadBitcoinCashElectrumServerList() async { Future<List<Node>> loadBitcoinCashElectrumServerList() async {
final serverListRaw = final serverListRaw = await rootBundle.loadString('assets/bitcoin_cash_electrum_server_list.yml');
await rootBundle.loadString('assets/bitcoin_cash_electrum_server_list.yml');
final loadedServerList = loadYaml(serverListRaw) as YamlList; final loadedServerList = loadYaml(serverListRaw) as YamlList;
final serverList = <Node>[]; final serverList = <Node>[];
@ -141,6 +140,7 @@ Future<List<Node>> loadDefaultPolygonNodes() async {
for (final raw in loadedNodes) { for (final raw in loadedNodes) {
if (raw is Map) { if (raw is Map) {
final node = Node.fromMap(Map<String, Object>.from(raw)); final node = Node.fromMap(Map<String, Object>.from(raw));
node.type = WalletType.polygon; node.type = WalletType.polygon;
nodes.add(node); nodes.add(node);
} }
@ -159,7 +159,6 @@ Future<void> resetToDefault(Box<Node> nodeSource) async {
final nanoNodes = await loadDefaultNanoNodes(); final nanoNodes = await loadDefaultNanoNodes();
final polygonNodes = await loadDefaultPolygonNodes(); final polygonNodes = await loadDefaultPolygonNodes();
final nodes = moneroNodes + final nodes = moneroNodes +
bitcoinElectrumServerList + bitcoinElectrumServerList +
litecoinElectrumServerList + litecoinElectrumServerList +

View file

@ -20,6 +20,8 @@ class PreferencesKey {
static const disableBuyKey = 'disable_buy'; static const disableBuyKey = 'disable_buy';
static const disableSellKey = 'disable_sell'; static const disableSellKey = 'disable_sell';
static const defaultBuyProvider = 'default_buy_provider'; static const defaultBuyProvider = 'default_buy_provider';
static const walletListOrder = 'wallet_list_order';
static const walletListAscending = 'wallet_list_ascending';
static const currentFiatApiModeKey = 'current_fiat_api_mode'; static const currentFiatApiModeKey = 'current_fiat_api_mode';
static const shouldStartTorOnLaunch = 'start_tor_on_launch'; static const shouldStartTorOnLaunch = 'start_tor_on_launch';
static const allowBiometricalAuthenticationKey = 'allow_biometrical_authentication'; static const allowBiometricalAuthenticationKey = 'allow_biometrical_authentication';

View file

@ -0,0 +1,22 @@
import 'package:cake_wallet/generated/i18n.dart';
enum WalletListOrderType {
CreationDate,
Alphabetical,
GroupByType,
Custom;
@override
String toString() {
switch (this) {
case WalletListOrderType.CreationDate:
return S.current.creation_date;
case WalletListOrderType.Alphabetical:
return S.current.alphabetical;
case WalletListOrderType.GroupByType:
return S.current.group_by_type;
case WalletListOrderType.Custom:
return S.current.custom_drag;
}
}
}

View file

@ -159,8 +159,8 @@ class SideShiftExchangeProvider extends ExchangeProvider {
url = apiBaseUrl + orderPath + '/fixed'; url = apiBaseUrl + orderPath + '/fixed';
} else { } else {
url = apiBaseUrl + orderPath + '/variable'; url = apiBaseUrl + orderPath + '/variable';
body["depositCoin"] = request.fromCurrency.title.toLowerCase(); body["depositCoin"] = _normalizeCurrency(request.fromCurrency);
body["settleCoin"] = request.toCurrency.title.toLowerCase(); body["settleCoin"] = _normalizeCurrency(request.toCurrency);
body["settleNetwork"] = _networkFor(request.toCurrency); body["settleNetwork"] = _networkFor(request.toCurrency);
body["depositNetwork"] = _networkFor(request.fromCurrency); body["depositNetwork"] = _networkFor(request.fromCurrency);
} }
@ -248,8 +248,8 @@ class SideShiftExchangeProvider extends ExchangeProvider {
final url = apiBaseUrl + quotePath; final url = apiBaseUrl + quotePath;
final headers = {'Content-Type': 'application/json'}; final headers = {'Content-Type': 'application/json'};
final body = { final body = {
'depositCoin': request.fromCurrency.title.toLowerCase(), 'depositCoin': _normalizeCurrency(request.fromCurrency),
'settleCoin': request.toCurrency.title.toLowerCase(), 'settleCoin': _normalizeCurrency(request.toCurrency),
'affiliateId': affiliateId, 'affiliateId': affiliateId,
'settleAmount': request.toAmount, 'settleAmount': request.toAmount,
'settleNetwork': _networkFor(request.toCurrency), 'settleNetwork': _networkFor(request.toCurrency),
@ -274,6 +274,15 @@ class SideShiftExchangeProvider extends ExchangeProvider {
return responseJSON['id'] as String; return responseJSON['id'] as String;
} }
String _normalizeCurrency(CryptoCurrency currency) {
switch (currency) {
case CryptoCurrency.usdcEPoly:
return 'usdc';
default:
return currency.title.toLowerCase();
}
}
String _networkFor(CryptoCurrency currency) => String _networkFor(CryptoCurrency currency) =>
currency.tag != null ? _normalizeTag(currency.tag!) : 'mainnet'; currency.tag != null ? _normalizeTag(currency.tag!) : 'mainnet';

View file

@ -222,6 +222,10 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
return 'usdttrc20'; return 'usdttrc20';
case CryptoCurrency.usdcpoly: case CryptoCurrency.usdcpoly:
return 'usdcpoly'; return 'usdcpoly';
case CryptoCurrency.usdtPoly:
return 'usdtpoly';
case CryptoCurrency.usdcEPoly:
return 'usdcepoly';
case CryptoCurrency.usdcsol: case CryptoCurrency.usdcsol:
return 'usdcspl'; return 'usdcspl';
case CryptoCurrency.matic: case CryptoCurrency.matic:

View file

@ -272,6 +272,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
case CryptoCurrency.maticpoly: case CryptoCurrency.maticpoly:
return 'Mainnet'; return 'Mainnet';
case CryptoCurrency.usdcpoly: case CryptoCurrency.usdcpoly:
case CryptoCurrency.usdtPoly:
case CryptoCurrency.usdcEPoly:
return 'MATIC'; return 'MATIC';
case CryptoCurrency.zec: case CryptoCurrency.zec:
return 'Mainnet'; return 'Mainnet';
@ -284,6 +286,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
switch (currency) { switch (currency) {
case CryptoCurrency.zec: case CryptoCurrency.zec:
return 'zec'; return 'zec';
case CryptoCurrency.usdcEPoly:
return 'usdce';
default: default:
return currency.title.toLowerCase(); return currency.title.toLowerCase();
} }

View file

@ -44,3 +44,14 @@ String getChainNameBasedOnWalletType(WalletType walletType) {
return ''; return '';
} }
} }
String getTokenNameBasedOnWalletType(WalletType walletType) {
switch (walletType) {
case WalletType.ethereum:
return 'ETH';
case WalletType.polygon:
return 'MATIC';
default:
return '';
}
}

View file

@ -135,6 +135,7 @@ class ContactListPage extends BasePage {
await showBar<void>(context, S.of(context).copied_to_clipboard); await showBar<void>(context, S.of(context).copied_to_clipboard);
} }
}, },
behavior: HitTestBehavior.opaque,
child: Container( child: Container(
padding: const EdgeInsets.only(top: 16, bottom: 16, right: 24), padding: const EdgeInsets.only(top: 16, bottom: 16, right: 24),
child: Row( child: Row(

View file

@ -7,6 +7,7 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sideba
import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart'; import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart'; import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
import 'package:cake_wallet/src/widgets/gradient_background.dart'; import 'package:cake_wallet/src/widgets/gradient_background.dart';
import 'package:cake_wallet/src/widgets/vulnerable_seeds_popup.dart';
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart'; import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/utils/version_comparator.dart'; import 'package:cake_wallet/utils/version_comparator.dart';
@ -60,7 +61,8 @@ class DashboardPage extends StatelessWidget {
); );
if (DeviceInfo.instance.isDesktop) { if (DeviceInfo.instance.isDesktop) {
if (responsiveLayoutUtil.screenWidth > ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) { if (responsiveLayoutUtil.screenWidth >
ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) {
return getIt.get<DesktopSidebarWrapper>(); return getIt.get<DesktopSidebarWrapper>();
} else { } else {
return dashboardPageView; return dashboardPageView;
@ -295,6 +297,8 @@ class _DashboardPageView extends BasePage {
_showReleaseNotesPopup(context); _showReleaseNotesPopup(context);
_showVulnerableSeedsPopup(context);
var needToPresentYat = false; var needToPresentYat = false;
var isInactive = false; var isInactive = false;
@ -354,4 +358,22 @@ class _DashboardPageView extends BasePage {
sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion); sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
} }
} }
void _showVulnerableSeedsPopup(BuildContext context) async {
final List<String> affectedWalletNames = await dashboardViewModel.checkAffectedWallets();
if (affectedWalletNames.isNotEmpty) {
Future<void>.delayed(
Duration(seconds: 1),
() {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return VulnerableSeedsPopup(affectedWalletNames);
},
);
},
);
}
}
} }

View file

@ -3,6 +3,7 @@ import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart'; import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart';
import 'package:cake_wallet/src/screens/yat_emoji_id.dart'; import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
import 'package:cake_wallet/src/widgets/vulnerable_seeds_popup.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/utils/version_comparator.dart'; import 'package:cake_wallet/utils/version_comparator.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -110,5 +111,25 @@ class DesktopDashboardPage extends StatelessWidget {
} else if (isNewInstall!) { } else if (isNewInstall!) {
sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion); sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
} }
_showVulnerableSeedsPopup(context);
}
void _showVulnerableSeedsPopup(BuildContext context) async {
final List<String> affectedWalletNames = await dashboardViewModel.checkAffectedWallets();
if (affectedWalletNames.isNotEmpty) {
Future<void>.delayed(
Duration(seconds: 1),
() {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return VulnerableSeedsPopup(affectedWalletNames);
},
);
},
);
}
} }
} }

View file

@ -8,6 +8,7 @@ import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
import 'package:cake_wallet/themes/extensions/address_theme.dart'; import 'package:cake_wallet/themes/extensions/address_theme.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/themes/extensions/menu_theme.dart'; import 'package:cake_wallet/themes/extensions/menu_theme.dart';
import 'package:cake_wallet/themes/extensions/picker_theme.dart'; import 'package:cake_wallet/themes/extensions/picker_theme.dart';
import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart';
@ -91,7 +92,7 @@ class HomeSettingsPage extends BasePage {
fillColor: Theme.of(context).cardColor, fillColor: Theme.of(context).cardColor,
child: Icon( child: Icon(
Icons.add, Icons.add,
color: Theme.of(context).dialogTheme.backgroundColor, color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
size: 22.0, size: 22.0,
), ),
padding: EdgeInsets.all(12), padding: EdgeInsets.all(12),

View file

@ -54,6 +54,24 @@ class BalancePage extends StatelessWidget {
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor, Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
height: 1, height: 1,
), ),
unselectedLabelStyle: TextStyle(
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color:
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
height: 1,
),
labelColor:
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
dividerColor:
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
indicatorColor:
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
unselectedLabelColor: Theme.of(context)
.extension<DashboardPageTheme>()!
.pageTitleTextColor
.withOpacity(0.5),
tabs: [ tabs: [
Tab(text: 'My Crypto'), Tab(text: 'My Crypto'),
Tab(text: 'My NFTs'), Tab(text: 'My NFTs'),

View file

@ -0,0 +1,158 @@
import 'package:cake_wallet/entities/list_order_mode.dart';
import 'package:cake_wallet/entities/wallet_list_order_types.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/src/widgets/section_divider.dart';
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
class FilterListWidget extends StatefulWidget {
FilterListWidget({
required this.initalType,
required this.initalAscending,
required this.onClose,
});
final WalletListOrderType? initalType;
final bool initalAscending;
final Function(bool, WalletListOrderType) onClose;
@override
FilterListWidgetState createState() => FilterListWidgetState();
}
class FilterListWidgetState extends State<FilterListWidget> {
late bool ascending;
late WalletListOrderType? type;
@override
void initState() {
super.initState();
ascending = widget.initalAscending;
type = widget.initalType;
}
void setSelectedOrderType(WalletListOrderType? orderType) {
setState(() {
type = orderType;
});
}
@override
Widget build(BuildContext context) {
const sectionDivider = const HorizontalSectionDivider();
return PickerWrapperWidget(
onClose: () {
widget.onClose(ascending, type!);
Navigator.of(context).pop();
},
children: [
Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(24)),
child: Container(
color: Theme.of(context).extension<CakeMenuTheme>()!.backgroundColor,
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Padding(
padding: EdgeInsets.all(24.0),
child: Text(
S.of(context).order_by,
style: TextStyle(
color:
Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
fontSize: 16,
fontFamily: 'Lato',
decoration: TextDecoration.none,
),
),
),
if (type != WalletListOrderType.Custom) ...[
sectionDivider,
SettingsChoicesCell(
ChoicesListItem<ListOrderMode>(
title: "",
items: ListOrderMode.all,
selectedItem: ascending ? ListOrderMode.ascending : ListOrderMode.descending,
onItemSelected: (ListOrderMode listOrderMode) {
setState(() {
ascending = listOrderMode == ListOrderMode.ascending;
});
},
),
),
],
sectionDivider,
RadioListTile(
value: WalletListOrderType.CreationDate,
groupValue: type,
title: Text(
WalletListOrderType.CreationDate.toString(),
style: TextStyle(
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none),
),
onChanged: setSelectedOrderType,
activeColor: Theme.of(context).primaryColor,
),
RadioListTile(
value: WalletListOrderType.Alphabetical,
groupValue: type,
title: Text(
WalletListOrderType.Alphabetical.toString(),
style: TextStyle(
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none),
),
onChanged: setSelectedOrderType,
activeColor: Theme.of(context).primaryColor,
),
RadioListTile(
value: WalletListOrderType.GroupByType,
groupValue: type,
title: Text(
WalletListOrderType.GroupByType.toString(),
style: TextStyle(
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none),
),
onChanged: setSelectedOrderType,
activeColor: Theme.of(context).primaryColor,
),
RadioListTile(
value: WalletListOrderType.Custom,
groupValue: type,
title: Text(
WalletListOrderType.Custom.toString(),
style: TextStyle(
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none),
),
onChanged: setSelectedOrderType,
activeColor: Theme.of(context).primaryColor,
),
]),
),
),
)
],
);
}
}

View file

@ -18,6 +18,7 @@ class HomeScreenAccountWidget extends StatelessWidget {
context: context, context: context,
builder: (_) => getIt.get<MoneroAccountListPage>()); builder: (_) => getIt.get<MoneroAccountListPage>());
}, },
behavior: HitTestBehavior.opaque,
child: Container( child: Container(
height: 100.0, height: 100.0,
child: Row( child: Row(

View file

@ -411,10 +411,6 @@ class ExchangePage extends BasePage {
} }
}); });
reaction((_) => exchangeViewModel.isReceiveAddressEnabled, (bool isEnabled) {
receiveKey.currentState!.isAddressEditable(isEditable: isEnabled);
});
reaction((_) => exchangeViewModel.isReceiveAmountEditable, (bool isReceiveAmountEditable) { reaction((_) => exchangeViewModel.isReceiveAmountEditable, (bool isReceiveAmountEditable) {
receiveKey.currentState!.isAmountEditable(isEditable: isReceiveAmountEditable); receiveKey.currentState!.isAmountEditable(isEditable: isReceiveAmountEditable);
}); });
@ -670,7 +666,6 @@ class ExchangePage extends BasePage {
? exchangeViewModel.wallet.walletAddresses.address ? exchangeViewModel.wallet.walletAddresses.address
: exchangeViewModel.receiveAddress, : exchangeViewModel.receiveAddress,
initialIsAmountEditable: exchangeViewModel.isReceiveAmountEditable, initialIsAmountEditable: exchangeViewModel.isReceiveAmountEditable,
initialIsAddressEditable: exchangeViewModel.isReceiveAddressEnabled,
isAmountEstimated: true, isAmountEstimated: true,
isMoneroWallet: exchangeViewModel.isMoneroWallet, isMoneroWallet: exchangeViewModel.isMoneroWallet,
currencies: exchangeViewModel.receiveCurrencies, currencies: exchangeViewModel.receiveCurrencies,

View file

@ -174,8 +174,6 @@ class ExchangeTemplatePage extends BasePage {
? exchangeViewModel.wallet.walletAddresses.address ? exchangeViewModel.wallet.walletAddresses.address
: exchangeViewModel.receiveAddress, : exchangeViewModel.receiveAddress,
initialIsAmountEditable: false, initialIsAmountEditable: false,
initialIsAddressEditable:
exchangeViewModel.isReceiveAddressEnabled,
isAmountEstimated: true, isAmountEstimated: true,
isMoneroWallet: exchangeViewModel.isMoneroWallet, isMoneroWallet: exchangeViewModel.isMoneroWallet,
currencies: exchangeViewModel.receiveCurrencies, currencies: exchangeViewModel.receiveCurrencies,
@ -328,11 +326,6 @@ class ExchangeTemplatePage extends BasePage {
} }
}); });
reaction((_) => exchangeViewModel.isReceiveAddressEnabled,
(bool isEnabled) {
receiveKey.currentState!.isAddressEditable(isEditable: isEnabled);
});
reaction((_) => exchangeViewModel.provider, (ExchangeProvider? provider) { reaction((_) => exchangeViewModel.provider, (ExchangeProvider? provider) {
receiveKey.currentState!.isAmountEditable(isEditable: false); receiveKey.currentState!.isAmountEditable(isEditable: false);
}); });

View file

@ -23,7 +23,6 @@ class ExchangeCard extends StatefulWidget {
required this.initialAddress, required this.initialAddress,
required this.initialWalletName, required this.initialWalletName,
required this.initialIsAmountEditable, required this.initialIsAmountEditable,
required this.initialIsAddressEditable,
required this.isAmountEstimated, required this.isAmountEstimated,
required this.currencies, required this.currencies,
required this.onCurrencySelected, required this.onCurrencySelected,
@ -31,6 +30,7 @@ class ExchangeCard extends StatefulWidget {
this.currencyValueValidator, this.currencyValueValidator,
this.addressTextFieldValidator, this.addressTextFieldValidator,
this.title = '', this.title = '',
this.initialIsAddressEditable = true,
this.hasRefundAddress = false, this.hasRefundAddress = false,
this.isMoneroWallet = false, this.isMoneroWallet = false,
this.currencyButtonColor = Colors.transparent, this.currencyButtonColor = Colors.transparent,

View file

@ -176,7 +176,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
); );
launchUri = null; launchUri = null;
} else { } else {
_nonETHWalletErrorToast(S.current.switchToETHWallet); _nonETHWalletErrorToast(S.current.switchToEVMCompatibleWallet);
} }
} }
@ -206,7 +206,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
String? _getRouteToGo() { String? _getRouteToGo() {
if (isWalletConnectLink) { if (isWalletConnectLink) {
if (isEVMCompatibleChain(widget.appStore.wallet!.type)) { if (isEVMCompatibleChain(widget.appStore.wallet!.type)) {
_nonETHWalletErrorToast(S.current.switchToETHWallet); _nonETHWalletErrorToast(S.current.switchToEVMCompatibleWallet);
return null; return null;
} }
return Routes.walletConnectConnectionsListing; return Routes.walletConnectConnectionsListing;

View file

@ -1,4 +1,3 @@
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart'; import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
@ -18,12 +17,11 @@ import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
class ConnectionSyncPage extends BasePage { class ConnectionSyncPage extends BasePage {
ConnectionSyncPage(this.dashboardViewModel, this.web3walletService); ConnectionSyncPage(this.dashboardViewModel);
@override @override
String get title => S.current.connection_sync; String get title => S.current.connection_sync;
final Web3WalletService? web3walletService;
final DashboardViewModel dashboardViewModel; final DashboardViewModel dashboardViewModel;
@override @override

View file

@ -76,7 +76,7 @@ class DisplaySettingsPage extends BasePage {
}, },
), ),
if (responsiveLayoutUtil.shouldRenderMobileUI && DeviceInfo.instance.isMobile) if (responsiveLayoutUtil.shouldRenderMobileUI && DeviceInfo.instance.isMobile)
SettingsThemeChoicesCell(_displaySettingsViewModel), Semantics(label: S.current.color_theme, child: SettingsThemeChoicesCell(_displaySettingsViewModel)),
], ],
), ),
); );

View file

@ -17,56 +17,57 @@ class SettingsChoicesCell extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( if (choicesListItem.title.isNotEmpty) ...[
children: [ Row(
Text( children: [
choicesListItem.title, Text(
style: TextStyle( choicesListItem.title,
fontSize: 14, style: TextStyle(
fontWeight: FontWeight.normal, fontSize: 14,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor, fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
), ),
), ],
], ),
), const SizedBox(height: 24),
const SizedBox(height: 24), ],
Center( Center(
child: SingleChildScrollView( child: Container(
scrollDirection: Axis.horizontal, decoration: BoxDecoration(
child: Container( borderRadius: BorderRadius.circular(30),
decoration: BoxDecoration( color: Theme.of(context).extension<AddressTheme>()!.actionButtonColor,
borderRadius: BorderRadius.circular(30), ),
color: Theme.of(context).extension<AddressTheme>()!.actionButtonColor, child: Row(
), mainAxisAlignment: MainAxisAlignment.center,
child: Row( children: choicesListItem.items.map((dynamic e) {
mainAxisAlignment: MainAxisAlignment.center, final isSelected = choicesListItem.selectedItem == e;
children: choicesListItem.items.map((dynamic e) { return Expanded(
final isSelected = choicesListItem.selectedItem == e; child: GestureDetector(
return GestureDetector(
onTap: () { onTap: () {
choicesListItem.onItemSelected.call(e); choicesListItem.onItemSelected.call(e);
}, },
child: Container( child: Container(
padding: EdgeInsets.symmetric(horizontal: 32, vertical: 8), padding: EdgeInsets.symmetric(vertical: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30), borderRadius: BorderRadius.circular(30),
color: isSelected color: isSelected ? Theme.of(context).primaryColor : null,
? Theme.of(context).primaryColor
: null,
), ),
child: Text( child: Center(
choicesListItem.displayItem.call(e), child: Text(
style: TextStyle( choicesListItem.displayItem.call(e),
color: isSelected style: TextStyle(
? Colors.white color: isSelected
: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor, ? Colors.white
fontWeight: isSelected ? FontWeight.w700 : FontWeight.normal, : Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
fontWeight: isSelected ? FontWeight.w700 : FontWeight.normal,
),
), ),
), ),
), ),
); ),
}).toList(), );
), }).toList(),
), ),
), ),
), ),

View file

@ -54,57 +54,61 @@ class SettingsThemeChoicesCell extends StatelessWidget {
return Padding( return Padding(
padding: EdgeInsets.all(5), padding: EdgeInsets.all(5),
child: GestureDetector( child: Semantics(
onTap: () { label: e.toString(),
_displaySettingsViewModel.setTheme(e); selected: isSelected,
}, child: GestureDetector(
child: Container( onTap: () {
padding: EdgeInsets.all(5), _displaySettingsViewModel.setTheme(e);
decoration: BoxDecoration( },
borderRadius: BorderRadius.circular(cellRadius), child: Container(
border: isSelected padding: EdgeInsets.all(5),
? Border.all( decoration: BoxDecoration(
color: Theme.of(context).primaryColor) borderRadius: BorderRadius.circular(cellRadius),
: null, border: isSelected
color: Theme.of(context) ? Border.all(
.extension<CakeTextTheme>()! color: Theme.of(context).primaryColor)
.secondaryTextColor : null,
.withOpacity( color: Theme.of(context)
currentTheme.brightness == Brightness.light .extension<CakeTextTheme>()!
? 0.1 .secondaryTextColor
: 0.3), .withOpacity(
), currentTheme.brightness == Brightness.light
child: Row( ? 0.1
mainAxisAlignment: MainAxisAlignment.center, : 0.3),
children: [ ),
Container( child: Row(
padding: EdgeInsets.symmetric( mainAxisAlignment: MainAxisAlignment.center,
horizontal: cellWidth, vertical: cellHeight), children: [
decoration: BoxDecoration( Container(
borderRadius: BorderRadius.only( padding: EdgeInsets.symmetric(
topLeft: Radius.circular(cellRadius), horizontal: cellWidth, vertical: cellHeight),
bottomLeft: Radius.circular(cellRadius)), decoration: BoxDecoration(
color: e.themeData.primaryColor, borderRadius: BorderRadius.only(
topLeft: Radius.circular(cellRadius),
bottomLeft: Radius.circular(cellRadius)),
color: e.themeData.primaryColor,
),
), ),
), Container(
Container( padding: EdgeInsets.symmetric(
padding: EdgeInsets.symmetric( horizontal: cellWidth, vertical: cellHeight),
horizontal: cellWidth, vertical: cellHeight), decoration: BoxDecoration(
decoration: BoxDecoration( color: e.themeData.colorScheme.background,
color: e.themeData.colorScheme.background, ),
), ),
), Container(
Container( padding: EdgeInsets.symmetric(
padding: EdgeInsets.symmetric( horizontal: cellWidth, vertical: cellHeight),
horizontal: cellWidth, vertical: cellHeight), decoration: BoxDecoration(
decoration: BoxDecoration( borderRadius: BorderRadius.only(
borderRadius: BorderRadius.only( topRight: Radius.circular(cellRadius),
topRight: Radius.circular(cellRadius), bottomRight: Radius.circular(cellRadius)),
bottomRight: Radius.circular(cellRadius)), color: e.themeData.cardColor,
color: e.themeData.cardColor, ),
), ),
), ],
], ),
), ),
), ),
), ),

View file

@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
class FilteredList extends StatefulWidget {
FilteredList({
required this.list,
required this.itemBuilder,
required this.updateFunction,
});
final ObservableList<dynamic> list;
final Widget Function(BuildContext, int) itemBuilder;
final Function updateFunction;
@override
FilteredListState createState() => FilteredListState();
}
class FilteredListState extends State<FilteredList> {
@override
Widget build(BuildContext context) {
return Observer(
builder: (_) => ReorderableListView.builder(
physics: const BouncingScrollPhysics(),
itemBuilder: widget.itemBuilder,
itemCount: widget.list.length,
onReorder: (int oldIndex, int newIndex) {
if (oldIndex < newIndex) {
newIndex -= 1;
}
final dynamic item = widget.list.removeAt(oldIndex);
widget.list.insert(newIndex, item);
widget.updateFunction();
},
),
);
}
}

View file

@ -1,8 +1,15 @@
import 'package:cake_wallet/entities/wallet_list_order_types.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_list_widget.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_widget.dart';
import 'package:cake_wallet/src/screens/wallet_list/filtered_list.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/themes/extensions/filter_theme.dart';
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart'; import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:another_flushbar/flushbar.dart'; import 'package:another_flushbar/flushbar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -28,6 +35,53 @@ class WalletListPage extends BasePage {
@override @override
Widget body(BuildContext context) => Widget body(BuildContext context) =>
WalletListBody(walletListViewModel: walletListViewModel, authService: authService); WalletListBody(walletListViewModel: walletListViewModel, authService: authService);
@override
Widget trailing(BuildContext context) {
final filterIcon = Image.asset('assets/images/filter_icon.png',
color: Theme.of(context).extension<FilterTheme>()!.iconColor);
return MergeSemantics(
child: SizedBox(
height: 37,
width: 37,
child: ButtonTheme(
minWidth: double.minPositive,
child: Semantics(
container: true,
child: GestureDetector(
onTap: () async {
await showPopUp<void>(
context: context,
builder: (context) => FilterListWidget(
initalType: walletListViewModel.orderType,
initalAscending: walletListViewModel.ascending,
onClose: (bool ascending, WalletListOrderType type) async {
walletListViewModel.setAscending(ascending);
await walletListViewModel.setOrderType(type);
},
),
);
},
child: Semantics(
label: 'Transaction Filter',
button: true,
enabled: true,
child: Container(
height: 36,
width: 36,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context).extension<FilterTheme>()!.buttonColor,
),
child: filterIcon,
),
),
),
),
),
),
);
}
} }
class WalletListBody extends StatefulWidget { class WalletListBody extends StatefulWidget {
@ -70,11 +124,9 @@ class WalletListBodyState extends State<WalletListBody> {
Expanded( Expanded(
child: Container( child: Container(
child: Observer( child: Observer(
builder: (_) => ListView.separated( builder: (_) => FilteredList(
physics: const BouncingScrollPhysics(), list: widget.walletListViewModel.wallets,
separatorBuilder: (_, index) => updateFunction: widget.walletListViewModel.reorderAccordingToWalletList,
Divider(color: Theme.of(context).colorScheme.background, height: 32),
itemCount: widget.walletListViewModel.wallets.length,
itemBuilder: (__, index) { itemBuilder: (__, index) {
final wallet = widget.walletListViewModel.wallets[index]; final wallet = widget.walletListViewModel.wallets[index];
final currentColor = wallet.isCurrent final currentColor = wallet.isCurrent
@ -83,6 +135,7 @@ class WalletListBodyState extends State<WalletListBody> {
.createNewWalletButtonBackgroundColor .createNewWalletButtonBackgroundColor
: Theme.of(context).colorScheme.background; : Theme.of(context).colorScheme.background;
final row = GestureDetector( final row = GestureDetector(
key: ValueKey(wallet.name),
onTap: () => wallet.isCurrent ? null : _loadWallet(wallet), onTap: () => wallet.isCurrent ? null : _loadWallet(wallet),
child: Container( child: Container(
height: tileHeight, height: tileHeight,
@ -117,7 +170,7 @@ class WalletListBodyState extends State<WalletListBody> {
maxLines: null, maxLines: null,
softWrap: true, softWrap: true,
style: TextStyle( style: TextStyle(
fontSize: 22, fontSize: 20,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Theme.of(context) color: Theme.of(context)
.extension<CakeTextTheme>()! .extension<CakeTextTheme>()!
@ -137,13 +190,15 @@ class WalletListBodyState extends State<WalletListBody> {
return wallet.isCurrent return wallet.isCurrent
? row ? row
: Row( : Row(
key: ValueKey(wallet.name),
children: [ children: [
Expanded(child: row), Expanded(child: row),
GestureDetector( GestureDetector(
onTap: () => Navigator.of(context).pushNamed(Routes.walletEdit, onTap: () => Navigator.of(context).pushNamed(Routes.walletEdit,
arguments: [widget.walletListViewModel, wallet]), arguments: [widget.walletListViewModel, wallet]),
child: Container( child: Container(
padding: EdgeInsets.only(right: 20), padding: EdgeInsets.only(
right: DeviceInfo.instance.isMobile ? 20 : 40),
child: Center( child: Center(
child: Container( child: Container(
height: 40, height: 40,

View file

@ -4,10 +4,11 @@ import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart'; import 'package:cake_wallet/src/widgets/alert_close_button.dart';
class PickerWrapperWidget extends StatelessWidget { class PickerWrapperWidget extends StatelessWidget {
PickerWrapperWidget({required this.children, this.hasTitle = false}); PickerWrapperWidget({required this.children, this.hasTitle = false, this.onClose});
final List<Widget> children; final List<Widget> children;
final bool hasTitle; final bool hasTitle;
final Function()? onClose;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -45,7 +46,7 @@ class PickerWrapperWidget extends StatelessWidget {
children: children, children: children,
), ),
SizedBox(height: ResponsiveLayoutUtilBase.kPopupSpaceHeight), SizedBox(height: ResponsiveLayoutUtilBase.kPopupSpaceHeight),
AlertCloseButton(bottom: closeButtonBottom), AlertCloseButton(bottom: closeButtonBottom, onTap: onClose),
], ],
), ),
), ),

View file

@ -14,25 +14,29 @@ class StandardSwitch extends StatefulWidget {
class StandardSwitchState extends State<StandardSwitch> { class StandardSwitchState extends State<StandardSwitch> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector(
onTap: widget.onTaped, return Semantics(
child: AnimatedContainer( toggled: widget.value,
padding: EdgeInsets.only(left: 2.0, right: 2.0), child: GestureDetector(
alignment: widget.value ? Alignment.centerRight : Alignment.centerLeft, onTap: widget.onTaped,
duration: Duration(milliseconds: 250), child: AnimatedContainer(
width: 50, padding: EdgeInsets.only(left: 2.0, right: 2.0),
height: 28, alignment: widget.value ? Alignment.centerRight : Alignment.centerLeft,
decoration: BoxDecoration( duration: Duration(milliseconds: 250),
color: widget.value width: 50,
? Theme.of(context).primaryColor height: 28,
: Theme.of(context).disabledColor,
borderRadius: BorderRadius.all(Radius.circular(14.0))),
child: Container(
width: 24.0,
height: 24.0,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: widget.value
shape: BoxShape.circle), ? Theme.of(context).primaryColor
: Theme.of(context).disabledColor,
borderRadius: BorderRadius.all(Radius.circular(14.0))),
child: Container(
width: 24.0,
height: 24.0,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle),
),
), ),
), ),
); );

View file

@ -0,0 +1,91 @@
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
import 'package:flutter/material.dart';
class VulnerableSeedsPopup extends StatelessWidget {
final List<String> affectedWalletNames;
const VulnerableSeedsPopup(this.affectedWalletNames, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
AlertBackground(
child: AlertDialog(
insetPadding: EdgeInsets.only(left: 16, right: 16, bottom: 48),
elevation: 0.0,
contentPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(30))),
content: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
gradient: LinearGradient(colors: [
Theme.of(context).extension<DashboardPageTheme>()!.firstGradientBackgroundColor,
Theme.of(context)
.extension<DashboardPageTheme>()!
.secondGradientBackgroundColor,
], begin: Alignment.centerLeft, end: Alignment.centerRight)),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Stack(
children: [
SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Container(
alignment: Alignment.bottomCenter,
child: DefaultTextStyle(
style: TextStyle(
decoration: TextDecoration.none,
fontSize: 24.0,
fontWeight: FontWeight.bold,
fontFamily: 'Lato',
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
),
child: Text("Emergency Notice"),
),
),
),
),
SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(top: 48, bottom: 16),
child: Container(
width: double.maxFinite,
child: Column(
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.7,
),
child: Text(
"Your Bitcoin wallet(s) below use a legacy seed format that is vulnerable, which MAY result in you losing money from these wallet(s) if no action is taken.\nWe recommend that you IMMEDIATELY create wallet(s) in Cake Wallet and immediately transfer the funds to these wallet(s).\nVulnerable wallet name(s):\n\n[${affectedWalletNames.join(", ")}]\n\nFor assistance, please use the in-app support or email support@cakewallet.com",
style: TextStyle(
decoration: TextDecoration.none,
fontSize: 16.0,
fontFamily: 'Lato',
color: Theme.of(context)
.extension<DashboardPageTheme>()!
.textColor,
),
),
)
],
),
),
),
),
],
),
),
),
),
),
AlertCloseButton(bottom: 30)
],
);
}
}

View file

@ -12,6 +12,7 @@ import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/entities/seed_phrase_length.dart'; import 'package:cake_wallet/entities/seed_phrase_length.dart';
import 'package:cake_wallet/entities/seed_type.dart'; import 'package:cake_wallet/entities/seed_type.dart';
import 'package:cake_wallet/entities/sort_balance_types.dart'; import 'package:cake_wallet/entities/sort_balance_types.dart';
import 'package:cake_wallet/entities/wallet_list_order_types.dart';
import 'package:cake_wallet/polygon/polygon.dart'; import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart'; import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
import 'package:cake_wallet/view_model/settings/sync_mode.dart'; import 'package:cake_wallet/view_model/settings/sync_mode.dart';
@ -53,7 +54,8 @@ abstract class SettingsStoreBase with Store {
required bool initialAppSecure, required bool initialAppSecure,
required bool initialDisableBuy, required bool initialDisableBuy,
required bool initialDisableSell, required bool initialDisableSell,
required BuyProviderType initialDefaultBuyProvider, required WalletListOrderType initialWalletListOrder,
required bool initialWalletListAscending,
required FiatApiMode initialFiatMode, required FiatApiMode initialFiatMode,
required bool initialShouldStartTorOnLaunch, required bool initialShouldStartTorOnLaunch,
required bool initialAllowBiometricalAuthentication, required bool initialAllowBiometricalAuthentication,
@ -124,6 +126,8 @@ abstract class SettingsStoreBase with Store {
isAppSecure = initialAppSecure, isAppSecure = initialAppSecure,
disableBuy = initialDisableBuy, disableBuy = initialDisableBuy,
disableSell = initialDisableSell, disableSell = initialDisableSell,
walletListOrder = initialWalletListOrder,
walletListAscending = initialWalletListAscending,
shouldShowMarketPlaceInDashboard = initialShouldShowMarketPlaceInDashboard, shouldShowMarketPlaceInDashboard = initialShouldShowMarketPlaceInDashboard,
exchangeStatus = initialExchangeStatus, exchangeStatus = initialExchangeStatus,
currentTheme = initialTheme, currentTheme = initialTheme,
@ -259,6 +263,16 @@ abstract class SettingsStoreBase with Store {
}); });
}); });
reaction(
(_) => walletListOrder,
(WalletListOrderType walletListOrder) =>
sharedPreferences.setInt(PreferencesKey.walletListOrder, walletListOrder.index));
reaction(
(_) => walletListAscending,
(bool walletListAscending) =>
sharedPreferences.setBool(PreferencesKey.walletListAscending, walletListAscending));
reaction( reaction(
(_) => autoGenerateSubaddressStatus, (_) => autoGenerateSubaddressStatus,
(AutoGenerateSubaddressStatus autoGenerateSubaddressStatus) => sharedPreferences.setInt( (AutoGenerateSubaddressStatus autoGenerateSubaddressStatus) => sharedPreferences.setInt(
@ -514,6 +528,12 @@ abstract class SettingsStoreBase with Store {
@observable @observable
bool disableSell; bool disableSell;
@observable
WalletListOrderType walletListOrder;
@observable
bool walletListAscending;
@observable @observable
bool allowBiometricalAuthentication; bool allowBiometricalAuthentication;
@ -728,8 +748,10 @@ abstract class SettingsStoreBase with Store {
final isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? false; final isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? false;
final disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? false; final disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? false;
final disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? false; final disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? false;
final defaultBuyProvider = final walletListOrder =
BuyProviderType.values[sharedPreferences.getInt(PreferencesKey.defaultBuyProvider) ?? 0]; WalletListOrderType.values[sharedPreferences.getInt(PreferencesKey.walletListOrder) ?? 0];
final walletListAscending =
sharedPreferences.getBool(PreferencesKey.walletListAscending) ?? true;
final currentFiatApiMode = FiatApiMode.deserialize( final currentFiatApiMode = FiatApiMode.deserialize(
raw: sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey) ?? raw: sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey) ??
FiatApiMode.enabled.raw); FiatApiMode.enabled.raw);
@ -909,7 +931,8 @@ abstract class SettingsStoreBase with Store {
initialAppSecure: isAppSecure, initialAppSecure: isAppSecure,
initialDisableBuy: disableBuy, initialDisableBuy: disableBuy,
initialDisableSell: disableSell, initialDisableSell: disableSell,
initialDefaultBuyProvider: defaultBuyProvider, initialWalletListOrder: walletListOrder,
initialWalletListAscending: walletListAscending,
initialFiatMode: currentFiatApiMode, initialFiatMode: currentFiatApiMode,
initialShouldStartTorOnLaunch: shouldStartTorOnLaunch, initialShouldStartTorOnLaunch: shouldStartTorOnLaunch,
initialAllowBiometricalAuthentication: allowBiometricalAuthentication, initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
@ -1026,6 +1049,9 @@ abstract class SettingsStoreBase with Store {
isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? isAppSecure; isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? isAppSecure;
disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? disableBuy; disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? disableBuy;
disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? disableSell; disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? disableSell;
walletListOrder =
WalletListOrderType.values[sharedPreferences.getInt(PreferencesKey.walletListOrder) ?? 0];
walletListAscending = sharedPreferences.getBool(PreferencesKey.walletListAscending) ?? true;
allowBiometricalAuthentication = allowBiometricalAuthentication =
sharedPreferences.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ?? sharedPreferences.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
allowBiometricalAuthentication; allowBiometricalAuthentication;

View file

@ -78,7 +78,7 @@ class BrightTheme extends LightTheme {
FilterTheme get filterTheme => super.filterTheme.copyWith( FilterTheme get filterTheme => super.filterTheme.copyWith(
checkboxSecondGradientColor: Palette.pinkFlamingo, checkboxSecondGradientColor: Palette.pinkFlamingo,
checkboxBackgroundColor: Colors.white, checkboxBackgroundColor: Colors.white,
buttonColor: Colors.white.withOpacity(0.2), buttonColor: Palette.darkGray.withOpacity(0.2),
iconColor: Colors.white); iconColor: Colors.white);
@override @override

View file

@ -91,6 +91,9 @@ abstract class ContactListViewModelBase with Store {
walletContacts.where((element) => _isValidForCurrency(element)).toList(); walletContacts.where((element) => _isValidForCurrency(element)).toList();
bool _isValidForCurrency(ContactBase element) { bool _isValidForCurrency(ContactBase element) {
return _currency == null || element.type == _currency || element.type.title == _currency!.tag; return _currency == null ||
element.type == _currency ||
element.type.title == _currency!.tag ||
element.type.tag == _currency!.tag;
} }
} }

View file

@ -1,3 +1,6 @@
import 'dart:convert';
import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart'; import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/balance_display_mode.dart'; import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/entities/buy_provider_types.dart'; import 'package:cake_wallet/entities/buy_provider_types.dart';
@ -24,12 +27,19 @@ import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart'; import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
import 'package:cake_wallet/view_model/settings/sync_mode.dart'; import 'package:cake_wallet/view_model/settings/sync_mode.dart';
import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cryptography/cryptography.dart';
import 'package:cw_core/balance.dart'; import 'package:cw_core/balance.dart';
import 'package:cw_core/cake_hive.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/utils/file.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:eth_sig_util/util/utils.dart';
import 'package:flutter/services.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
part 'dashboard_view_model.g.dart'; part 'dashboard_view_model.g.dart';
@ -46,7 +56,8 @@ abstract class DashboardViewModelBase with Store {
required this.settingsStore, required this.settingsStore,
required this.yatStore, required this.yatStore,
required this.ordersStore, required this.ordersStore,
required this.anonpayTransactionsStore}) required this.anonpayTransactionsStore,
required this.keyService})
: hasSellAction = false, : hasSellAction = false,
hasBuyAction = false, hasBuyAction = false,
hasExchangeAction = false, hasExchangeAction = false,
@ -262,6 +273,8 @@ abstract class DashboardViewModelBase with Store {
bool get hasRescan => wallet.type == WalletType.monero || wallet.type == WalletType.haven; bool get hasRescan => wallet.type == WalletType.monero || wallet.type == WalletType.haven;
final KeyService keyService;
BalanceViewModel balanceViewModel; BalanceViewModel balanceViewModel;
AppStore appStore; AppStore appStore;
@ -283,12 +296,12 @@ abstract class DashboardViewModelBase with Store {
Map<String, List<FilterItem>> filterItems; Map<String, List<FilterItem>> filterItems;
BuyProviderType get defaultBuyProvider => BuyProviderType get defaultBuyProvider =>
settingsStore.defaultBuyProviders[wallet.type] ?? settingsStore.defaultBuyProviders[wallet.type] ?? BuyProviderType.AskEachTime;
BuyProviderType.AskEachTime;
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled; bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;
List<BuyProviderType> get availableProviders => BuyProviderType.getAvailableProviders(wallet.type); List<BuyProviderType> get availableProviders =>
BuyProviderType.getAvailableProviders(wallet.type);
bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup; bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup;
@ -433,4 +446,32 @@ abstract class DashboardViewModelBase with Store {
@action @action
void setSyncAll(bool value) => settingsStore.currentSyncAll = value; void setSyncAll(bool value) => settingsStore.currentSyncAll = value;
Future<List<String>> checkAffectedWallets() async {
// await load file
final vulnerableSeedsString = await rootBundle.loadString('assets/text/cakewallet_weak_bitcoin_seeds_hashed_sorted_version1.txt');
final vulnerableSeeds = vulnerableSeedsString.split("\n");
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
List<String> affectedWallets = [];
for (var walletInfo in walletInfoSource.values) {
if (walletInfo.type == WalletType.bitcoin) {
final password = await keyService.getWalletPassword(walletName: walletInfo.name);
final path = await pathForWallet(name: walletInfo.name, type: walletInfo.type);
final jsonSource = await read(path: path, password: password);
final data = json.decode(jsonSource) as Map;
final mnemonic = data['mnemonic'] as String;
final hash = await Cryptography.instance.sha256().hash(utf8.encode(mnemonic));
final seedSha = bytesToHex(hash.bytes);
if (vulnerableSeeds.contains(seedSha)) {
affectedWallets.add(walletInfo.name);
}
}
}
return affectedWallets;
}
} }

View file

@ -66,7 +66,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
receiveAddress = '', receiveAddress = '',
depositAddress = '', depositAddress = '',
isDepositAddressEnabled = false, isDepositAddressEnabled = false,
isReceiveAddressEnabled = false,
isReceiveAmountEditable = false, isReceiveAmountEditable = false,
_useTorOnly = false, _useTorOnly = false,
receiveCurrencies = <CryptoCurrency>[], receiveCurrencies = <CryptoCurrency>[],
@ -108,7 +107,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
bestRateSync = Timer.periodic(Duration(seconds: 10), (timer) => _calculateBestRate()); bestRateSync = Timer.periodic(Duration(seconds: 10), (timer) => _calculateBestRate());
isDepositAddressEnabled = !(depositCurrency == wallet.currency); isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
depositAmount = ''; depositAmount = '';
receiveAmount = ''; receiveAmount = '';
receiveAddress = ''; receiveAddress = '';
@ -201,9 +199,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
@observable @observable
bool isDepositAddressEnabled; bool isDepositAddressEnabled;
@observable
bool isReceiveAddressEnabled;
@observable @observable
bool isReceiveAmountEntered; bool isReceiveAmountEntered;
@ -315,7 +310,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
isFixedRateMode = false; isFixedRateMode = false;
_onPairChange(); _onPairChange();
isDepositAddressEnabled = !(depositCurrency == wallet.currency); isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
} }
@action @action
@ -324,7 +318,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
isFixedRateMode = false; isFixedRateMode = false;
_onPairChange(); _onPairChange();
isDepositAddressEnabled = !(depositCurrency == wallet.currency); isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
} }
@action @action
@ -535,7 +528,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.address : ''; depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.address : '';
receiveAddress = receiveCurrency == wallet.currency ? wallet.walletAddresses.address : ''; receiveAddress = receiveCurrency == wallet.currency ? wallet.walletAddresses.address : '';
isDepositAddressEnabled = !(depositCurrency == wallet.currency); isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
isFixedRateMode = false; isFixedRateMode = false;
_onPairChange(); _onPairChange();
} }

View file

@ -1,5 +1,6 @@
import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/core/wallet_loading_service.dart'; import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cake_wallet/entities/wallet_list_order_types.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/app_store.dart';
@ -19,7 +20,7 @@ abstract class WalletListViewModelBase with Store {
this._walletLoadingService, this._walletLoadingService,
this._authService, this._authService,
) : wallets = ObservableList<WalletListItem>() { ) : wallets = ObservableList<WalletListItem>() {
updateList(); setOrderType(_appStore.settingsStore.walletListOrder);
reaction((_) => _appStore.wallet, (_) => updateList()); reaction((_) => _appStore.wallet, (_) => updateList());
} }
@ -43,11 +44,14 @@ abstract class WalletListViewModelBase with Store {
@action @action
Future<void> loadWallet(WalletListItem walletItem) async { Future<void> loadWallet(WalletListItem walletItem) async {
final wallet = final wallet = await _walletLoadingService.load(walletItem.type, walletItem.name);
await _walletLoadingService.load(walletItem.type, walletItem.name);
_appStore.changeCurrentWallet(wallet); _appStore.changeCurrentWallet(wallet);
} }
WalletListOrderType? get orderType => _appStore.settingsStore.walletListOrder;
bool get ascending => _appStore.settingsStore.walletListAscending;
@action @action
void updateList() { void updateList() {
wallets.clear(); wallets.clear();
@ -57,14 +61,105 @@ abstract class WalletListViewModelBase with Store {
name: info.name, name: info.name,
type: info.type, type: info.type,
key: info.key, key: info.key,
isCurrent: info.name == _appStore.wallet?.name && isCurrent: info.name == _appStore.wallet?.name && info.type == _appStore.wallet?.type,
info.type == _appStore.wallet?.type,
isEnabled: availableWalletTypes.contains(info.type), isEnabled: availableWalletTypes.contains(info.type),
), ),
), ),
); );
} }
Future<void> reorderAccordingToWalletList() async {
if (wallets.isEmpty) {
updateList();
return;
}
_appStore.settingsStore.walletListOrder = WalletListOrderType.Custom;
// make a copy of the walletInfoSource:
List<WalletInfo> walletInfoSourceCopy = _walletInfoSource.values.toList();
// delete all wallets from walletInfoSource:
await _walletInfoSource.clear();
// add wallets from wallets list in order of wallets list, by name:
for (WalletListItem wallet in wallets) {
for (int i = 0; i < walletInfoSourceCopy.length; i++) {
if (walletInfoSourceCopy[i].name == wallet.name) {
await _walletInfoSource.add(walletInfoSourceCopy[i]);
walletInfoSourceCopy.removeAt(i);
break;
}
}
}
updateList();
}
Future<void> sortGroupByType() async {
// sort the wallets by type:
List<WalletInfo> walletInfoSourceCopy = _walletInfoSource.values.toList();
await _walletInfoSource.clear();
if (ascending) {
walletInfoSourceCopy.sort((a, b) => a.type.toString().compareTo(b.type.toString()));
} else {
walletInfoSourceCopy.sort((a, b) => b.type.toString().compareTo(a.type.toString()));
}
await _walletInfoSource.addAll(walletInfoSourceCopy);
updateList();
}
Future<void> sortAlphabetically() async {
// sort the wallets alphabetically:
List<WalletInfo> walletInfoSourceCopy = _walletInfoSource.values.toList();
await _walletInfoSource.clear();
if (ascending) {
walletInfoSourceCopy.sort((a, b) => a.name.compareTo(b.name));
} else {
walletInfoSourceCopy.sort((a, b) => b.name.compareTo(a.name));
}
await _walletInfoSource.addAll(walletInfoSourceCopy);
updateList();
}
Future<void> sortByCreationDate() async {
// sort the wallets by creation date:
List<WalletInfo> walletInfoSourceCopy = _walletInfoSource.values.toList();
await _walletInfoSource.clear();
if (ascending) {
walletInfoSourceCopy.sort((a, b) => a.date.compareTo(b.date));
} else {
walletInfoSourceCopy.sort((a, b) => b.date.compareTo(a.date));
}
await _walletInfoSource.addAll(walletInfoSourceCopy);
updateList();
}
void setAscending(bool ascending) {
_appStore.settingsStore.walletListAscending = ascending;
}
Future<void> setOrderType(WalletListOrderType? type) async {
if (type == null) return;
_appStore.settingsStore.walletListOrder = type;
switch (type) {
case WalletListOrderType.CreationDate:
await sortByCreationDate();
break;
case WalletListOrderType.Alphabetical:
await sortAlphabetically();
break;
case WalletListOrderType.GroupByType:
await sortGroupByType();
break;
case WalletListOrderType.Custom:
default:
await reorderAccordingToWalletList();
break;
}
}
bool checkIfAuthRequired() { bool checkIfAuthRequired() {
return _authService.requireAuth(); return _authService.requireAuth();
} }

View file

@ -727,6 +727,9 @@
"require_for_exchanges_to_external_wallets": "ﺔﻴﺟﺭﺎﺧ ﻆﻓﺎﺤﻣ ﻰﻟﺇ ﺕﻻﺩﺎﺒﺘﻟﺍ ﺐﻠﻄﺘﺗ", "require_for_exchanges_to_external_wallets": "ﺔﻴﺟﺭﺎﺧ ﻆﻓﺎﺤﻣ ﻰﻟﺇ ﺕﻻﺩﺎﺒﺘﻟﺍ ﺐﻠﻄﺘﺗ",
"camera_permission_is_required": ".ﺍﺮﻴﻣﺎﻜﻟﺍ ﻥﺫﺇ ﺏﻮﻠﻄﻣ", "camera_permission_is_required": ".ﺍﺮﻴﻣﺎﻜﻟﺍ ﻥﺫﺇ ﺏﻮﻠﻄﻣ",
"switchToETHWallet": "ﻯﺮﺧﺃ ﺓﺮﻣ ﺔﻟﻭﺎﺤﻤﻟﺍﻭ Ethereum ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻰﺟﺮﻳ", "switchToETHWallet": "ﻯﺮﺧﺃ ﺓﺮﻣ ﺔﻟﻭﺎﺤﻤﻟﺍﻭ Ethereum ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻰﺟﺮﻳ",
"order_by": "ترتيب حسب",
"creation_date": "تاريخ الإنشاء",
"group_by_type": "مجموعة حسب النوع",
"importNFTs": "NFTs ﺩﺍﺮﻴﺘﺳﺍ", "importNFTs": "NFTs ﺩﺍﺮﻴﺘﺳﺍ",
"noNFTYet": "ﻥﻵﺍ ﻰﺘﺣ NFTs ﺪﺟﻮﻳ ﻻ", "noNFTYet": "ﻥﻵﺍ ﻰﺘﺣ NFTs ﺪﺟﻮﻳ ﻻ",
"address": " ﻥﺍﻮﻨﻋ", "address": " ﻥﺍﻮﻨﻋ",
@ -746,7 +749,11 @@
"seed_language_czech": "التشيكية", "seed_language_czech": "التشيكية",
"seed_language_korean": "الكورية", "seed_language_korean": "الكورية",
"seed_language_chinese_traditional": "تقاليد صينية)", "seed_language_chinese_traditional": "تقاليد صينية)",
"ascending": "تصاعدي",
"descending": "النزول",
"dfx_option_description": "ﺎﺑﻭﺭﻭﺃ ﻲﻓ ﺕﺎﻛﺮﺸﻟﺍﻭ ﺔﺋﺰﺠﺘﻟﺍ ءﻼﻤﻌﻟ .ﻲﻓﺎﺿﺇ KYC ﻥﻭﺪﺑ ﻭﺭﻮﻳ 990 ﻰﻟﺇ ﻞﺼﻳ ﺎﻣ .ﻱﺮﺴﻳﻮﺴﻟﺍ", "dfx_option_description": "ﺎﺑﻭﺭﻭﺃ ﻲﻓ ﺕﺎﻛﺮﺸﻟﺍﻭ ﺔﺋﺰﺠﺘﻟﺍ ءﻼﻤﻌﻟ .ﻲﻓﺎﺿﺇ KYC ﻥﻭﺪﺑ ﻭﺭﻮﻳ 990 ﻰﻟﺇ ﻞﺼﻳ ﺎﻣ .ﻱﺮﺴﻳﻮﺴﻟﺍ",
"polygonscan_history": "ﻥﺎﻜﺴﻧﻮﺠﻴﻟﻮﺑ ﺦﻳﺭﺎﺗ", "polygonscan_history": "ﻥﺎﻜﺴﻧﻮﺠﻴﻟﻮﺑ ﺦﻳﺭﺎﺗ",
"wallet_seed_legacy": "بذرة محفظة قديمة" "wallet_seed_legacy": "بذرة محفظة قديمة",
"custom_drag": "مخصص (عقد وسحب)",
"switchToEVMCompatibleWallet": " (Ethereum، Polygon) ﻯﺮﺧﺃ ﺓﺮﻣ ﺔﻟﻭﺎﺤﻤﻟﺍﻭ EVM ﻊﻣ ﺔﻘﻓﺍﻮﺘﻣ ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻰﺟﺮﻳ"
} }

View file

@ -723,6 +723,9 @@
"require_for_exchanges_to_external_wallets": "Изискване за обмен към външни портфейли", "require_for_exchanges_to_external_wallets": "Изискване за обмен към външни портфейли",
"camera_permission_is_required": "Изисква се разрешение за камерата.\nМоля, активирайте го от настройките на приложението.", "camera_permission_is_required": "Изисква се разрешение за камерата.\nМоля, активирайте го от настройките на приложението.",
"switchToETHWallet": "Моля, преминете към портфейл Ethereum и опитайте отново", "switchToETHWallet": "Моля, преминете към портфейл Ethereum и опитайте отново",
"order_by": "Подредени по",
"creation_date": "Дата на създаване",
"group_by_type": "Група по вид",
"importNFTs": "Импортирайте NFT", "importNFTs": "Импортирайте NFT",
"noNFTYet": "Все още няма NFT", "noNFTYet": "Все още няма NFT",
"address": "Адрес", "address": "Адрес",
@ -742,7 +745,11 @@
"seed_language_czech": "Чех", "seed_language_czech": "Чех",
"seed_language_korean": "Корейски", "seed_language_korean": "Корейски",
"seed_language_chinese_traditional": "Традиционен китайски)", "seed_language_chinese_traditional": "Традиционен китайски)",
"ascending": "Възходящ",
"descending": "Низходящ",
"dfx_option_description": "Купете крипто с EUR и CHF. До 990 € без допълнителен KYC. За клиенти на дребно и корпоративни клиенти в Европа", "dfx_option_description": "Купете крипто с EUR и CHF. До 990 € без допълнителен KYC. За клиенти на дребно и корпоративни клиенти в Европа",
"polygonscan_history": "История на PolygonScan", "polygonscan_history": "История на PolygonScan",
"wallet_seed_legacy": "Наследено портфейл семе" "wallet_seed_legacy": "Наследено портфейл семе",
"custom_drag": "Персонализиране (задръжте и плъзнете)",
"switchToEVMCompatibleWallet": "Моля, превключете към портфейл, съвместим с EVM, и опитайте отново (Ethereum, Polygon)"
} }

View file

@ -723,6 +723,9 @@
"require_for_exchanges_to_external_wallets": "Vyžadovat pro výměny do externích peněženek", "require_for_exchanges_to_external_wallets": "Vyžadovat pro výměny do externích peněženek",
"camera_permission_is_required": "Vyžaduje se povolení fotoaparátu.\nPovolte jej v nastavení aplikace.", "camera_permission_is_required": "Vyžaduje se povolení fotoaparátu.\nPovolte jej v nastavení aplikace.",
"switchToETHWallet": "Přejděte na peněženku Ethereum a zkuste to znovu", "switchToETHWallet": "Přejděte na peněženku Ethereum a zkuste to znovu",
"order_by": "Seřadit podle",
"creation_date": "Datum vzniku",
"group_by_type": "Skupina podle typu",
"importNFTs": "Importujte NFT", "importNFTs": "Importujte NFT",
"noNFTYet": "Zatím žádné NFT", "noNFTYet": "Zatím žádné NFT",
"address": "Adresa", "address": "Adresa",
@ -742,7 +745,11 @@
"seed_language_czech": "čeština", "seed_language_czech": "čeština",
"seed_language_korean": "korejština", "seed_language_korean": "korejština",
"seed_language_chinese_traditional": "Číňan (tradiční)", "seed_language_chinese_traditional": "Číňan (tradiční)",
"ascending": "Vzestupné",
"descending": "Klesající",
"dfx_option_description": "Nakupujte kryptoměny za EUR a CHF. Až 990 € bez dalších KYC. Pro maloobchodní a firemní zákazníky v Evropě", "dfx_option_description": "Nakupujte kryptoměny za EUR a CHF. Až 990 € bez dalších KYC. Pro maloobchodní a firemní zákazníky v Evropě",
"polygonscan_history": "Historie PolygonScan", "polygonscan_history": "Historie PolygonScan",
"wallet_seed_legacy": "Starší semeno peněženky" "wallet_seed_legacy": "Starší semeno peněženky",
"custom_drag": "Custom (Hold and Drag)",
"switchToEVMCompatibleWallet": "Přepněte na peněženku kompatibilní s EVM a zkuste to znovu (Ethereum, Polygon)"
} }

View file

@ -731,6 +731,9 @@
"require_for_exchanges_to_external_wallets": "Erforderlich für den Umtausch in externe Wallets", "require_for_exchanges_to_external_wallets": "Erforderlich für den Umtausch in externe Wallets",
"camera_permission_is_required": "Eine Kameraerlaubnis ist erforderlich.\nBitte aktivieren Sie es in den App-Einstellungen.", "camera_permission_is_required": "Eine Kameraerlaubnis ist erforderlich.\nBitte aktivieren Sie es in den App-Einstellungen.",
"switchToETHWallet": "Bitte wechseln Sie zu einem Ethereum-Wallet und versuchen Sie es erneut", "switchToETHWallet": "Bitte wechseln Sie zu einem Ethereum-Wallet und versuchen Sie es erneut",
"order_by": "Sortieren nach",
"creation_date": "Erstellungsdatum",
"group_by_type": "Gruppe nach Typ",
"importNFTs": "NFTs importieren", "importNFTs": "NFTs importieren",
"noNFTYet": "Noch keine NFTs", "noNFTYet": "Noch keine NFTs",
"address": "Adresse", "address": "Adresse",
@ -750,7 +753,11 @@
"seed_language_czech": "Tschechisch", "seed_language_czech": "Tschechisch",
"seed_language_korean": "Koreanisch", "seed_language_korean": "Koreanisch",
"seed_language_chinese_traditional": "Chinesisch (Traditionell)", "seed_language_chinese_traditional": "Chinesisch (Traditionell)",
"ascending": "Aufsteigend",
"descending": "Absteigend",
"dfx_option_description": "Krypto mit EUR und CHF kaufen. Bis zu 990€ ohne zusätzliches KYC. Für Privat- und Firmenkunden in Europa", "dfx_option_description": "Krypto mit EUR und CHF kaufen. Bis zu 990€ ohne zusätzliches KYC. Für Privat- und Firmenkunden in Europa",
"polygonscan_history": "PolygonScan-Verlauf", "polygonscan_history": "PolygonScan-Verlauf",
"wallet_seed_legacy": "Legacy Wallet Seed" "wallet_seed_legacy": "Legacy Wallet Seed",
"custom_drag": "Custom (Hold and Drag)",
"switchToEVMCompatibleWallet": "Bitte wechseln Sie zu einem EVM-kompatiblen Wallet und versuchen Sie es erneut (Ethereum, Polygon)"
} }

View file

@ -498,7 +498,7 @@
"bill_amount": "Bill Amount", "bill_amount": "Bill Amount",
"you_pay": "You Pay", "you_pay": "You Pay",
"tip": "Tip:", "tip": "Tip:",
"custom": "custom", "custom": "Custom",
"by_cake_pay": "by Cake Pay", "by_cake_pay": "by Cake Pay",
"expires": "Expires", "expires": "Expires",
"mm": "MM", "mm": "MM",
@ -732,6 +732,9 @@
"require_for_exchanges_to_external_wallets": "Require for exchanges to external wallets", "require_for_exchanges_to_external_wallets": "Require for exchanges to external wallets",
"camera_permission_is_required": "Camera permission is required. \nPlease enable it from app settings.", "camera_permission_is_required": "Camera permission is required. \nPlease enable it from app settings.",
"switchToETHWallet": "Please switch to an Ethereum wallet and try again", "switchToETHWallet": "Please switch to an Ethereum wallet and try again",
"order_by": "Order by",
"creation_date": "Creation Date",
"group_by_type": "Group by type",
"importNFTs": "Import NFTs", "importNFTs": "Import NFTs",
"noNFTYet": "No NFTs yet", "noNFTYet": "No NFTs yet",
"address": "Address", "address": "Address",
@ -751,7 +754,11 @@
"seed_language_czech": "Czech", "seed_language_czech": "Czech",
"seed_language_korean": "Korean", "seed_language_korean": "Korean",
"seed_language_chinese_traditional": "Chinese (Traditional)", "seed_language_chinese_traditional": "Chinese (Traditional)",
"ascending": "Ascending",
"descending": "Descending",
"dfx_option_description": "Buy crypto with EUR & CHF. Up to 990€ without additional KYC. For retail and corporate customers in Europe", "dfx_option_description": "Buy crypto with EUR & CHF. Up to 990€ without additional KYC. For retail and corporate customers in Europe",
"polygonscan_history": "PolygonScan history", "polygonscan_history": "PolygonScan history",
"wallet_seed_legacy": "Legacy wallet seed" "wallet_seed_legacy": "Legacy wallet seed",
"custom_drag": "Custom (Hold and Drag)",
"switchToEVMCompatibleWallet": "Please switch to an EVM compatible wallet and try again (Ethereum, Polygon)"
} }

View file

@ -731,6 +731,9 @@
"require_for_exchanges_to_external_wallets": "Requerido para intercambios a billeteras externas", "require_for_exchanges_to_external_wallets": "Requerido para intercambios a billeteras externas",
"camera_permission_is_required": "Se requiere permiso de la cámara.\nHabilítelo desde la configuración de la aplicación.", "camera_permission_is_required": "Se requiere permiso de la cámara.\nHabilítelo desde la configuración de la aplicación.",
"switchToETHWallet": "Cambie a una billetera Ethereum e inténtelo nuevamente.", "switchToETHWallet": "Cambie a una billetera Ethereum e inténtelo nuevamente.",
"order_by": "Ordenar",
"creation_date": "Fecha de creación",
"group_by_type": "Grupo por tipo",
"importNFTs": "Importar NFT", "importNFTs": "Importar NFT",
"noNFTYet": "Aún no hay NFT", "noNFTYet": "Aún no hay NFT",
"address": "DIRECCIÓN", "address": "DIRECCIÓN",
@ -749,9 +752,12 @@
"seedtype_polyseed": "Polieta (16 palabras)", "seedtype_polyseed": "Polieta (16 palabras)",
"seed_language_czech": "checo", "seed_language_czech": "checo",
"seed_language_korean": "coreano", "seed_language_korean": "coreano",
"seed_language_chinese_traditional": "Chino tradicional)", "ascending": "Ascendente",
"dfx_option_description": "Compre criptomonedas con EUR y CHF. Hasta 990€ sin KYC adicional. Para clientes minoristas y corporativos en Europa", "descending": "Descendente",
"seed_language_chinese_traditional": "Chino (tradicional)", "seed_language_chinese_traditional": "Chino (tradicional)",
"dfx_option_description": "Compre criptomonedas con EUR y CHF. Hasta 990€ sin KYC adicional. Para clientes minoristas y corporativos en Europa",
"polygonscan_history": "Historial de PolygonScan", "polygonscan_history": "Historial de PolygonScan",
"wallet_seed_legacy": "Semilla de billetera heredada" "wallet_seed_legacy": "Semilla de billetera heredada",
"custom_drag": "Custom (mantenía y arrastre)",
"switchToEVMCompatibleWallet": "Cambie a una billetera compatible con EVM e inténtelo nuevamente (Ethereum, Polygon)"
} }

View file

@ -730,7 +730,6 @@
"domain_looks_up": "Résolution de nom", "domain_looks_up": "Résolution de nom",
"require_for_exchanges_to_external_wallets": "Exiger pour les échanges vers des portefeuilles externes", "require_for_exchanges_to_external_wallets": "Exiger pour les échanges vers des portefeuilles externes",
"camera_permission_is_required": "L'autorisation de la caméra est requise.\nVeuillez l'activer à partir des paramètres de l'application.", "camera_permission_is_required": "L'autorisation de la caméra est requise.\nVeuillez l'activer à partir des paramètres de l'application.",
"switchToETHWallet": "Veuillez passer à un portefeuille (wallet) Ethereum et réessayer",
"importNFTs": "Importer des NFT", "importNFTs": "Importer des NFT",
"noNFTYet": "Pas encore de NFT", "noNFTYet": "Pas encore de NFT",
"address": "Adresse", "address": "Adresse",
@ -741,7 +740,11 @@
"seed_phrase_length": "Longueur de la phrase de départ", "seed_phrase_length": "Longueur de la phrase de départ",
"unavailable_balance": "Solde indisponible", "unavailable_balance": "Solde indisponible",
"unavailable_balance_description": "Solde indisponible : ce total comprend les fonds bloqués dans les transactions en attente et ceux que vous avez activement gelés dans vos paramètres de contrôle des pièces. Les soldes bloqués deviendront disponibles une fois leurs transactions respectives terminées, tandis que les soldes gelés resteront inaccessibles aux transactions jusqu'à ce que vous décidiez de les débloquer.", "unavailable_balance_description": "Solde indisponible : ce total comprend les fonds bloqués dans les transactions en attente et ceux que vous avez activement gelés dans vos paramètres de contrôle des pièces. Les soldes bloqués deviendront disponibles une fois leurs transactions respectives terminées, tandis que les soldes gelés resteront inaccessibles aux transactions jusqu'à ce que vous décidiez de les débloquer.",
"switchToETHWallet": "Veuillez passer à un portefeuille (wallet) Ethereum et réessayer",
"unspent_change": "Changement", "unspent_change": "Changement",
"order_by": "Commandé par",
"creation_date": "Date de création",
"group_by_type": "Groupe par type",
"tor_connection": "Connexion Tor", "tor_connection": "Connexion Tor",
"seed_hex_form": "Graine du portefeuille (forme hexagonale)", "seed_hex_form": "Graine du portefeuille (forme hexagonale)",
"seedtype": "Type de type graine", "seedtype": "Type de type graine",
@ -750,7 +753,11 @@
"seed_language_czech": "tchèque", "seed_language_czech": "tchèque",
"seed_language_korean": "coréen", "seed_language_korean": "coréen",
"seed_language_chinese_traditional": "Chinois (Traditionnel)", "seed_language_chinese_traditional": "Chinois (Traditionnel)",
"ascending": "Ascendant",
"descending": "Descendant",
"dfx_option_description": "Achetez des crypto-monnaies avec EUR et CHF. Jusqu'à 990€ sans KYC supplémentaire. Pour les clients particuliers et entreprises en Europe", "dfx_option_description": "Achetez des crypto-monnaies avec EUR et CHF. Jusqu'à 990€ sans KYC supplémentaire. Pour les clients particuliers et entreprises en Europe",
"polygonscan_history": "Historique de PolygonScan", "polygonscan_history": "Historique de PolygonScan",
"wallet_seed_legacy": "Graine de portefeuille hérité" "wallet_seed_legacy": "Graine de portefeuille hérité",
"custom_drag": "Custom (maintenir et traîner)",
"switchToEVMCompatibleWallet": "Veuillez passer à un portefeuille compatible EVM et réessayer (Ethereum, Polygon)"
} }

View file

@ -709,6 +709,9 @@
"require_for_exchanges_to_external_wallets": "Bukatar musanya zuwa wallet na waje", "require_for_exchanges_to_external_wallets": "Bukatar musanya zuwa wallet na waje",
"camera_permission_is_required": "Ana buƙatar izinin kyamara.\nDa fatan za a kunna shi daga saitunan app.", "camera_permission_is_required": "Ana buƙatar izinin kyamara.\nDa fatan za a kunna shi daga saitunan app.",
"switchToETHWallet": "Da fatan za a canza zuwa walat ɗin Ethereum kuma a sake gwadawa", "switchToETHWallet": "Da fatan za a canza zuwa walat ɗin Ethereum kuma a sake gwadawa",
"order_by": "Oda ta",
"creation_date": "Ranar halitta",
"group_by_type": "Rukuni ta nau'in",
"importNFTs": "Shigo da NFTs", "importNFTs": "Shigo da NFTs",
"noNFTYet": "Babu NFTs tukuna", "noNFTYet": "Babu NFTs tukuna",
"address": "Adireshi", "address": "Adireshi",
@ -728,7 +731,11 @@
"seed_language_czech": "Czech", "seed_language_czech": "Czech",
"seed_language_korean": "Yaren Koriya", "seed_language_korean": "Yaren Koriya",
"seed_language_chinese_traditional": "Sinanci (na gargajiya)", "seed_language_chinese_traditional": "Sinanci (na gargajiya)",
"ascending": "Hau",
"descending": "Saukowa",
"dfx_option_description": "Sayi crypto tare da EUR & CHF. Har zuwa € 990 ba tare da ƙarin KYC ba. Don 'yan kasuwa da abokan ciniki na kamfanoni a Turai", "dfx_option_description": "Sayi crypto tare da EUR & CHF. Har zuwa € 990 ba tare da ƙarin KYC ba. Don 'yan kasuwa da abokan ciniki na kamfanoni a Turai",
"polygonscan_history": "PolygonScan tarihin kowane zamani", "polygonscan_history": "PolygonScan tarihin kowane zamani",
"wallet_seed_legacy": "Tallarin walat walat" "wallet_seed_legacy": "Tallarin walat walat",
"custom_drag": "Al'ada (riƙe da ja)",
"switchToEVMCompatibleWallet": "Da fatan za a canza zuwa walat ɗin EVM mai jituwa kuma a sake gwadawa (Ethereum, Polygon)"
} }

View file

@ -731,6 +731,9 @@
"require_for_exchanges_to_external_wallets": "बाहरी वॉलेट में एक्सचेंज की आवश्यकता है", "require_for_exchanges_to_external_wallets": "बाहरी वॉलेट में एक्सचेंज की आवश्यकता है",
"camera_permission_is_required": "कैमरे की अनुमति आवश्यक है.\nकृपया इसे ऐप सेटिंग से सक्षम करें।", "camera_permission_is_required": "कैमरे की अनुमति आवश्यक है.\nकृपया इसे ऐप सेटिंग से सक्षम करें।",
"switchToETHWallet": "कृपया एथेरियम वॉलेट पर स्विच करें और पुनः प्रयास करें", "switchToETHWallet": "कृपया एथेरियम वॉलेट पर स्विच करें और पुनः प्रयास करें",
"order_by": "द्वारा आदेश",
"creation_date": "निर्माण तिथि",
"group_by_type": "प्रकार द्वारा समूह",
"importNFTs": "एनएफटी आयात करें", "importNFTs": "एनएफटी आयात करें",
"noNFTYet": "अभी तक कोई एनएफटी नहीं", "noNFTYet": "अभी तक कोई एनएफटी नहीं",
"address": "पता", "address": "पता",
@ -750,7 +753,11 @@
"seed_language_czech": "चेक", "seed_language_czech": "चेक",
"seed_language_korean": "कोरियाई", "seed_language_korean": "कोरियाई",
"seed_language_chinese_traditional": "चीनी पारंपरिक)", "seed_language_chinese_traditional": "चीनी पारंपरिक)",
"ascending": "आरोही",
"descending": "अवरोही",
"dfx_option_description": "EUR और CHF के साथ क्रिप्टो खरीदें। अतिरिक्त केवाईसी के बिना 990€ तक। यूरोप में खुदरा और कॉर्पोरेट ग्राहकों के लिए", "dfx_option_description": "EUR और CHF के साथ क्रिप्टो खरीदें। अतिरिक्त केवाईसी के बिना 990€ तक। यूरोप में खुदरा और कॉर्पोरेट ग्राहकों के लिए",
"polygonscan_history": "पॉलीगॉनस्कैन इतिहास", "polygonscan_history": "पॉलीगॉनस्कैन इतिहास",
"wallet_seed_legacy": "विरासत बटुए बीज" "wallet_seed_legacy": "विरासत बटुए बीज",
"custom_drag": "कस्टम (पकड़ और खींचें)",
"switchToEVMCompatibleWallet": "कृपया ईवीएम संगत वॉलेट पर स्विच करें और पुनः प्रयास करें (एथेरियम, पॉलीगॉन)"
} }

View file

@ -729,6 +729,9 @@
"require_for_exchanges_to_external_wallets": "Zahtijeva razmjene na vanjske novčanike", "require_for_exchanges_to_external_wallets": "Zahtijeva razmjene na vanjske novčanike",
"camera_permission_is_required": "Potrebno je dopuštenje kamere.\nOmogućite ga u postavkama aplikacije.", "camera_permission_is_required": "Potrebno je dopuštenje kamere.\nOmogućite ga u postavkama aplikacije.",
"switchToETHWallet": "Prijeđite na Ethereum novčanik i pokušajte ponovno", "switchToETHWallet": "Prijeđite na Ethereum novčanik i pokušajte ponovno",
"order_by": "Narediti",
"creation_date": "Datum stvaranja",
"group_by_type": "Grupirati",
"importNFTs": "Uvoz NFT-ova", "importNFTs": "Uvoz NFT-ova",
"noNFTYet": "Još nema NFT-ova", "noNFTYet": "Još nema NFT-ova",
"address": "Adresa", "address": "Adresa",
@ -747,9 +750,12 @@
"seedtype_polyseed": "Poliseed (16 riječi)", "seedtype_polyseed": "Poliseed (16 riječi)",
"seed_language_czech": "češki", "seed_language_czech": "češki",
"seed_language_korean": "korejski", "seed_language_korean": "korejski",
"seed_language_chinese_traditional": "Kinesko tradicionalno)", "ascending": "Uzlazni",
"dfx_option_description": "Kupujte kripto s EUR i CHF. Do 990 € bez dodatnog KYC-a. Za maloprodajne i poslovne korisnike u Europi", "descending": "Silazni",
"seed_language_chinese_traditional": "Kinesko (tradicionalno)", "seed_language_chinese_traditional": "Kinesko (tradicionalno)",
"dfx_option_description": "Kupujte kripto s EUR i CHF. Do 990 € bez dodatnog KYC-a. Za maloprodajne i poslovne korisnike u Europi",
"polygonscan_history": "Povijest PolygonScan", "polygonscan_history": "Povijest PolygonScan",
"wallet_seed_legacy": "Sjeme naslijeđenog novčanika" "wallet_seed_legacy": "Sjeme naslijeđenog novčanika",
"custom_drag": "Prilagođeni (držite i povucite)",
"switchToEVMCompatibleWallet": "Prijeđite na novčanik kompatibilan s EVM-om i pokušajte ponovno (Ethereum, Polygon)"
} }

View file

@ -719,6 +719,9 @@
"require_for_exchanges_to_external_wallets": "Memerlukan pertukaran ke dompet eksternal", "require_for_exchanges_to_external_wallets": "Memerlukan pertukaran ke dompet eksternal",
"camera_permission_is_required": "Izin kamera diperlukan.\nSilakan aktifkan dari pengaturan aplikasi.", "camera_permission_is_required": "Izin kamera diperlukan.\nSilakan aktifkan dari pengaturan aplikasi.",
"switchToETHWallet": "Silakan beralih ke dompet Ethereum dan coba lagi", "switchToETHWallet": "Silakan beralih ke dompet Ethereum dan coba lagi",
"order_by": "Dipesan oleh",
"creation_date": "Tanggal Pembuatan",
"group_by_type": "Grup demi jenis",
"importNFTs": "Impor NFT", "importNFTs": "Impor NFT",
"noNFTYet": "Belum ada NFT", "noNFTYet": "Belum ada NFT",
"address": "Alamat", "address": "Alamat",
@ -737,9 +740,12 @@
"seedtype_polyseed": "Polyseed (16 kata)", "seedtype_polyseed": "Polyseed (16 kata)",
"seed_language_czech": "Ceko", "seed_language_czech": "Ceko",
"seed_language_korean": "Korea", "seed_language_korean": "Korea",
"seed_language_chinese_traditional": "Cina tradisional)", "ascending": "Naik",
"dfx_option_description": "Beli kripto dengan EUR & CHF. Hingga 990€ tanpa KYC tambahan. Untuk pelanggan ritel dan korporat di Eropa", "descending": "Menurun",
"seed_language_chinese_traditional": "Cina (tradisional)", "seed_language_chinese_traditional": "Cina (tradisional)",
"dfx_option_description": "Beli kripto dengan EUR & CHF. Hingga 990€ tanpa KYC tambahan. Untuk pelanggan ritel dan korporat di Eropa",
"polygonscan_history": "Sejarah PolygonScan", "polygonscan_history": "Sejarah PolygonScan",
"wallet_seed_legacy": "Biji dompet warisan" "wallet_seed_legacy": "Biji dompet warisan",
"custom_drag": "Khusus (tahan dan seret)",
"switchToEVMCompatibleWallet": "Silakan beralih ke dompet yang kompatibel dengan EVM dan coba lagi (Ethereum, Polygon)"
} }

View file

@ -731,6 +731,9 @@
"require_for_exchanges_to_external_wallets": "Richiede scambi con portafogli esterni", "require_for_exchanges_to_external_wallets": "Richiede scambi con portafogli esterni",
"camera_permission_is_required": "È richiesta l'autorizzazione della fotocamera.\nAbilitalo dalle impostazioni dell'app.", "camera_permission_is_required": "È richiesta l'autorizzazione della fotocamera.\nAbilitalo dalle impostazioni dell'app.",
"switchToETHWallet": "Passa a un portafoglio Ethereum e riprova", "switchToETHWallet": "Passa a un portafoglio Ethereum e riprova",
"order_by": "Ordinato da",
"creation_date": "Data di creazione",
"group_by_type": "Gruppo per tipo",
"importNFTs": "Importa NFT", "importNFTs": "Importa NFT",
"noNFTYet": "Nessun NFT ancora", "noNFTYet": "Nessun NFT ancora",
"address": "Indirizzo", "address": "Indirizzo",
@ -750,7 +753,11 @@
"seed_language_czech": "ceco", "seed_language_czech": "ceco",
"seed_language_korean": "coreano", "seed_language_korean": "coreano",
"seed_language_chinese_traditional": "Cinese tradizionale)", "seed_language_chinese_traditional": "Cinese tradizionale)",
"ascending": "Ascendente",
"descending": "Discendente",
"dfx_option_description": "Acquista criptovalute con EUR e CHF. Fino a 990€ senza KYC aggiuntivi. Per clienti al dettaglio e aziendali in Europa", "dfx_option_description": "Acquista criptovalute con EUR e CHF. Fino a 990€ senza KYC aggiuntivi. Per clienti al dettaglio e aziendali in Europa",
"polygonscan_history": "Cronologia PolygonScan", "polygonscan_history": "Cronologia PolygonScan",
"wallet_seed_legacy": "Seme di portafoglio legacy" "wallet_seed_legacy": "Seme di portafoglio legacy",
"custom_drag": "Custom (Hold and Drag)",
"switchToEVMCompatibleWallet": "Passa a un portafoglio compatibile con EVM e riprova (Ethereum, Polygon)"
} }

View file

@ -731,6 +731,9 @@
"require_for_exchanges_to_external_wallets": "外部ウォレットへの交換に必要", "require_for_exchanges_to_external_wallets": "外部ウォレットへの交換に必要",
"camera_permission_is_required": "カメラの許可が必要です。\nアプリの設定から有効にしてください。", "camera_permission_is_required": "カメラの許可が必要です。\nアプリの設定から有効にしてください。",
"switchToETHWallet": "イーサリアムウォレットに切り替えてもう一度お試しください", "switchToETHWallet": "イーサリアムウォレットに切り替えてもう一度お試しください",
"order_by": "注文",
"creation_date": "作成日",
"group_by_type": "タイプごとにグループ",
"importNFTs": "NFTのインポート", "importNFTs": "NFTのインポート",
"noNFTYet": "NFTはまだありません", "noNFTYet": "NFTはまだありません",
"address": "住所", "address": "住所",
@ -750,7 +753,11 @@
"seed_language_czech": "チェコ", "seed_language_czech": "チェコ",
"seed_language_korean": "韓国語", "seed_language_korean": "韓国語",
"seed_language_chinese_traditional": "中国の伝統的な)", "seed_language_chinese_traditional": "中国の伝統的な)",
"ascending": "上昇",
"descending": "下降",
"dfx_option_description": "EUR と CHF で暗号通貨を購入します。追加のKYCなしで最大990ユーロ。ヨーロッパの小売および法人顧客向け", "dfx_option_description": "EUR と CHF で暗号通貨を購入します。追加のKYCなしで最大990ユーロ。ヨーロッパの小売および法人顧客向け",
"polygonscan_history": "ポリゴンスキャン履歴", "polygonscan_history": "ポリゴンスキャン履歴",
"wallet_seed_legacy": "レガシーウォレットシード" "wallet_seed_legacy": "レガシーウォレットシード",
"custom_drag": "カスタム(ホールドとドラッグ)",
"switchToEVMCompatibleWallet": "EVM 互換のウォレットに切り替えて再試行してください (イーサリアム、ポリゴン)"
} }

View file

@ -729,6 +729,9 @@
"require_for_exchanges_to_external_wallets": "외부 지갑으로의 교환을 위해 필요", "require_for_exchanges_to_external_wallets": "외부 지갑으로의 교환을 위해 필요",
"camera_permission_is_required": "카메라 권한이 필요합니다.\n앱 설정에서 활성화해 주세요.", "camera_permission_is_required": "카메라 권한이 필요합니다.\n앱 설정에서 활성화해 주세요.",
"switchToETHWallet": "이더리움 지갑으로 전환한 후 다시 시도해 주세요.", "switchToETHWallet": "이더리움 지갑으로 전환한 후 다시 시도해 주세요.",
"order_by": "주문",
"creation_date": "생산 일",
"group_by_type": "유형별 그룹",
"importNFTs": "NFT 가져오기", "importNFTs": "NFT 가져오기",
"noNFTYet": "아직 NFT가 없습니다", "noNFTYet": "아직 NFT가 없습니다",
"address": "주소", "address": "주소",
@ -748,7 +751,11 @@
"seed_language_czech": "체코 사람", "seed_language_czech": "체코 사람",
"seed_language_korean": "한국인", "seed_language_korean": "한국인",
"seed_language_chinese_traditional": "중국 전통)", "seed_language_chinese_traditional": "중국 전통)",
"ascending": "오름차순",
"descending": "내림차순",
"dfx_option_description": "EUR 및 CHF로 암호화폐를 구매하세요. 추가 KYC 없이 최대 990€. 유럽의 소매 및 기업 고객용", "dfx_option_description": "EUR 및 CHF로 암호화폐를 구매하세요. 추가 KYC 없이 최대 990€. 유럽의 소매 및 기업 고객용",
"polygonscan_history": "다각형 스캔 기록", "polygonscan_history": "다각형 스캔 기록",
"wallet_seed_legacy": "레거시 지갑 시드" "wallet_seed_legacy": "레거시 지갑 시드",
"custom_drag": "사용자 정의 (홀드 앤 드래그)",
"switchToEVMCompatibleWallet": "EVM 호환 지갑으로 전환 후 다시 시도해 주세요. (이더리움, 폴리곤)"
} }

View file

@ -729,6 +729,9 @@
"require_for_exchanges_to_external_wallets": "ပြင်ပပိုက်ဆံအိတ်များသို့ လဲလှယ်ရန် လိုအပ်သည်။", "require_for_exchanges_to_external_wallets": "ပြင်ပပိုက်ဆံအိတ်များသို့ လဲလှယ်ရန် လိုအပ်သည်။",
"camera_permission_is_required": "ကင်မရာခွင့်ပြုချက် လိုအပ်ပါသည်။\nအက်ပ်ဆက်တင်များမှ ၎င်းကိုဖွင့်ပါ။", "camera_permission_is_required": "ကင်မရာခွင့်ပြုချက် လိုအပ်ပါသည်။\nအက်ပ်ဆက်တင်များမှ ၎င်းကိုဖွင့်ပါ။",
"switchToETHWallet": "ကျေးဇူးပြု၍ Ethereum ပိုက်ဆံအိတ်သို့ ပြောင်းပြီး ထပ်စမ်းကြည့်ပါ။", "switchToETHWallet": "ကျေးဇူးပြု၍ Ethereum ပိုက်ဆံအိတ်သို့ ပြောင်းပြီး ထပ်စမ်းကြည့်ပါ။",
"order_by": "အမှာစာ",
"creation_date": "ဖန်တီးမှုနေ့စွဲ",
"group_by_type": "အမျိုးအစားအလိုက်အုပ်စုဖွဲ့",
"importNFTs": "NFTs များကို တင်သွင်းပါ။", "importNFTs": "NFTs များကို တင်သွင်းပါ။",
"noNFTYet": "NFTs မရှိသေးပါ။", "noNFTYet": "NFTs မရှိသေးပါ။",
"address": "လိပ်စာ", "address": "လိပ်စာ",
@ -748,7 +751,11 @@
"seed_language_czech": "ချက်", "seed_language_czech": "ချက်",
"seed_language_korean": "ကိုးရီးယား", "seed_language_korean": "ကိုးရီးယား",
"seed_language_chinese_traditional": "တရုတ်ရိုးရာ)", "seed_language_chinese_traditional": "တရုတ်ရိုးရာ)",
"ascending": "တက်",
"descending": "ဆင်း",
"dfx_option_description": "EUR & CHF ဖြင့် crypto ကိုဝယ်ပါ။ အပို KYC မပါဘဲ 990€ အထိ။ ဥရောပရှိ လက်လီရောင်းချသူများနှင့် ကော်ပိုရိတ်ဖောက်သည်များအတွက်", "dfx_option_description": "EUR & CHF ဖြင့် crypto ကိုဝယ်ပါ။ အပို KYC မပါဘဲ 990€ အထိ။ ဥရောပရှိ လက်လီရောင်းချသူများနှင့် ကော်ပိုရိတ်ဖောက်သည်များအတွက်",
"polygonscan_history": "PolygonScan မှတ်တမ်း", "polygonscan_history": "PolygonScan မှတ်တမ်း",
"wallet_seed_legacy": "အမွေအနှစ်ပိုက်ဆံအိတ်မျိုးစေ့" "wallet_seed_legacy": "အမွေအနှစ်ပိုက်ဆံအိတ်မျိုးစေ့",
"custom_drag": "စိတ်ကြိုက် (Drag)",
"switchToEVMCompatibleWallet": "ကျေးဇူးပြု၍ EVM တွဲဖက်သုံးနိုင်သော ပိုက်ဆံအိတ်သို့ ပြောင်းပြီး ထပ်စမ်းကြည့်ပါ (Ethereum၊ Polygon)"
} }

View file

@ -731,6 +731,9 @@
"require_for_exchanges_to_external_wallets": "Vereist voor uitwisselingen naar externe portemonnees", "require_for_exchanges_to_external_wallets": "Vereist voor uitwisselingen naar externe portemonnees",
"camera_permission_is_required": "Cameratoestemming is vereist.\nSchakel dit in via de app-instellingen.", "camera_permission_is_required": "Cameratoestemming is vereist.\nSchakel dit in via de app-instellingen.",
"switchToETHWallet": "Schakel over naar een Ethereum-portemonnee en probeer het opnieuw", "switchToETHWallet": "Schakel over naar een Ethereum-portemonnee en probeer het opnieuw",
"order_by": "Bestellen door",
"creation_date": "Aanmaakdatum",
"group_by_type": "Groep voor type",
"importNFTs": "NFT's importeren", "importNFTs": "NFT's importeren",
"noNFTYet": "Nog geen NFT's", "noNFTYet": "Nog geen NFT's",
"address": "Adres", "address": "Adres",
@ -749,9 +752,12 @@
"seedtype_polyseed": "Polyseed (16 woorden)", "seedtype_polyseed": "Polyseed (16 woorden)",
"seed_language_czech": "Tsjechisch", "seed_language_czech": "Tsjechisch",
"seed_language_korean": "Koreaans", "seed_language_korean": "Koreaans",
"seed_language_chinese_traditional": "Chinese traditionele)", "ascending": "Stijgend",
"dfx_option_description": "Koop crypto met EUR & CHF. Tot 990€ zonder extra KYC. Voor particuliere en zakelijke klanten in Europa", "descending": "Aflopend",
"seed_language_chinese_traditional": "Chinese (traditionele)", "seed_language_chinese_traditional": "Chinese (traditionele)",
"dfx_option_description": "Koop crypto met EUR & CHF. Tot 990€ zonder extra KYC. Voor particuliere en zakelijke klanten in Europa",
"polygonscan_history": "PolygonScan-geschiedenis", "polygonscan_history": "PolygonScan-geschiedenis",
"wallet_seed_legacy": "Legacy portemonnee zaad" "wallet_seed_legacy": "Legacy portemonnee zaad",
"custom_drag": "Custom (vasthouden en slepen)",
"switchToEVMCompatibleWallet": "Schakel over naar een EVM-compatibele portemonnee en probeer het opnieuw (Ethereum, Polygon)"
} }

View file

@ -731,6 +731,9 @@
"require_for_exchanges_to_external_wallets": "Wymagaj wymiany na portfele zewnętrzne", "require_for_exchanges_to_external_wallets": "Wymagaj wymiany na portfele zewnętrzne",
"camera_permission_is_required": "Wymagane jest pozwolenie na korzystanie z aparatu.\nWłącz tę funkcję w ustawieniach aplikacji.", "camera_permission_is_required": "Wymagane jest pozwolenie na korzystanie z aparatu.\nWłącz tę funkcję w ustawieniach aplikacji.",
"switchToETHWallet": "Przejdź na portfel Ethereum i spróbuj ponownie", "switchToETHWallet": "Przejdź na portfel Ethereum i spróbuj ponownie",
"order_by": "Zamów przez",
"creation_date": "Data utworzenia",
"group_by_type": "Grupa według typu",
"importNFTs": "Importuj NFT", "importNFTs": "Importuj NFT",
"noNFTYet": "Nie ma jeszcze NFT", "noNFTYet": "Nie ma jeszcze NFT",
"address": "Adres", "address": "Adres",
@ -750,7 +753,11 @@
"seed_language_czech": "Czech", "seed_language_czech": "Czech",
"seed_language_korean": "koreański", "seed_language_korean": "koreański",
"seed_language_chinese_traditional": "Chiński tradycyjny)", "seed_language_chinese_traditional": "Chiński tradycyjny)",
"ascending": "Wznoszący się",
"descending": "Schodzenie",
"dfx_option_description": "Kupuj kryptowaluty za EUR i CHF. Do 990 € bez dodatkowego KYC. Dla klientów detalicznych i korporacyjnych w Europie", "dfx_option_description": "Kupuj kryptowaluty za EUR i CHF. Do 990 € bez dodatkowego KYC. Dla klientów detalicznych i korporacyjnych w Europie",
"polygonscan_history": "Historia PolygonScan", "polygonscan_history": "Historia PolygonScan",
"wallet_seed_legacy": "Dziedziczne ziarno portfela" "wallet_seed_legacy": "Dziedziczne ziarno portfela",
"custom_drag": "Niestandardowe (trzymaj i przeciągnij)",
"switchToEVMCompatibleWallet": "Przejdź na portfel zgodny z EVM i spróbuj ponownie (Ethereum, Polygon)"
} }

View file

@ -730,6 +730,9 @@
"require_for_exchanges_to_external_wallets": "Exigir trocas para carteiras externas", "require_for_exchanges_to_external_wallets": "Exigir trocas para carteiras externas",
"camera_permission_is_required": "É necessária permissão da câmera.\nAtive-o nas configurações do aplicativo.", "camera_permission_is_required": "É necessária permissão da câmera.\nAtive-o nas configurações do aplicativo.",
"switchToETHWallet": "Mude para uma carteira Ethereum e tente novamente", "switchToETHWallet": "Mude para uma carteira Ethereum e tente novamente",
"order_by": "Ordenar por",
"creation_date": "Data de criação",
"group_by_type": "Grupo por tipo",
"importNFTs": "Importar NFTs", "importNFTs": "Importar NFTs",
"noNFTYet": "Ainda não há NFT", "noNFTYet": "Ainda não há NFT",
"address": "Endereço", "address": "Endereço",
@ -749,7 +752,11 @@
"seed_language_czech": "Tcheco", "seed_language_czech": "Tcheco",
"seed_language_korean": "coreano", "seed_language_korean": "coreano",
"seed_language_chinese_traditional": "Chinês tradicional)", "seed_language_chinese_traditional": "Chinês tradicional)",
"ascending": "Ascendente",
"descending": "descendente",
"dfx_option_description": "Compre criptografia com EUR e CHF. Até 990€ sem KYC adicional. Para clientes de varejo e corporativos na Europa", "dfx_option_description": "Compre criptografia com EUR e CHF. Até 990€ sem KYC adicional. Para clientes de varejo e corporativos na Europa",
"polygonscan_history": "História do PolygonScan", "polygonscan_history": "História do PolygonScan",
"wallet_seed_legacy": "Semente de carteira herdada" "wallet_seed_legacy": "Semente de carteira herdada",
"custom_drag": "Personalizado (segure e arraste)",
"switchToEVMCompatibleWallet": "Mude para uma carteira compatível com EVM e tente novamente (Ethereum, Polygon)"
} }

View file

@ -731,6 +731,9 @@
"require_for_exchanges_to_external_wallets": "Требовать обмена на внешние кошельки", "require_for_exchanges_to_external_wallets": "Требовать обмена на внешние кошельки",
"camera_permission_is_required": "Требуется разрешение камеры.\nПожалуйста, включите его в настройках приложения.", "camera_permission_is_required": "Требуется разрешение камеры.\nПожалуйста, включите его в настройках приложения.",
"switchToETHWallet": "Пожалуйста, переключитесь на кошелек Ethereum и повторите попытку.", "switchToETHWallet": "Пожалуйста, переключитесь на кошелек Ethereum и повторите попытку.",
"order_by": "Сортировать по",
"creation_date": "Дата создания",
"group_by_type": "Группа по типу",
"importNFTs": "Импортировать NFT", "importNFTs": "Импортировать NFT",
"noNFTYet": "NFT пока нет", "noNFTYet": "NFT пока нет",
"address": "Адрес", "address": "Адрес",
@ -750,7 +753,11 @@
"seed_language_czech": "Чешский", "seed_language_czech": "Чешский",
"seed_language_korean": "Корейский", "seed_language_korean": "Корейский",
"seed_language_chinese_traditional": "Китайский традиционный)", "seed_language_chinese_traditional": "Китайский традиционный)",
"ascending": "Восходящий",
"descending": "Нисходящий",
"dfx_option_description": "Покупайте криптовалюту за EUR и CHF. До 990€ без дополнительного KYC. Для розничных и корпоративных клиентов в Европе", "dfx_option_description": "Покупайте криптовалюту за EUR и CHF. До 990€ без дополнительного KYC. Для розничных и корпоративных клиентов в Европе",
"polygonscan_history": "История PolygonScan", "polygonscan_history": "История PolygonScan",
"wallet_seed_legacy": "Наследие семя кошелька" "wallet_seed_legacy": "Наследие семя кошелька",
"custom_drag": "Пользователь (удерживайте и перетаскивайте)",
"switchToEVMCompatibleWallet": "Пожалуйста, переключитесь на кошелек, совместимый с EVM, и повторите попытку (Ethereum, Polygon)."
} }

View file

@ -729,6 +729,9 @@
"require_for_exchanges_to_external_wallets": "จำเป็นต้องแลกเปลี่ยนกับกระเป๋าเงินภายนอก", "require_for_exchanges_to_external_wallets": "จำเป็นต้องแลกเปลี่ยนกับกระเป๋าเงินภายนอก",
"camera_permission_is_required": "ต้องได้รับอนุญาตจากกล้อง\nโปรดเปิดใช้งานจากการตั้งค่าแอป", "camera_permission_is_required": "ต้องได้รับอนุญาตจากกล้อง\nโปรดเปิดใช้งานจากการตั้งค่าแอป",
"switchToETHWallet": "โปรดเปลี่ยนไปใช้กระเป๋าเงิน Ethereum แล้วลองอีกครั้ง", "switchToETHWallet": "โปรดเปลี่ยนไปใช้กระเป๋าเงิน Ethereum แล้วลองอีกครั้ง",
"order_by": "สั่งโดย",
"creation_date": "วันที่สร้าง",
"group_by_type": "กลุ่มตามประเภท",
"importNFTs": "นำเข้า NFT", "importNFTs": "นำเข้า NFT",
"noNFTYet": "ยังไม่มี NFT", "noNFTYet": "ยังไม่มี NFT",
"address": "ที่อยู่", "address": "ที่อยู่",
@ -748,7 +751,11 @@
"seed_language_czech": "ภาษาเช็ก", "seed_language_czech": "ภาษาเช็ก",
"seed_language_korean": "เกาหลี", "seed_language_korean": "เกาหลี",
"seed_language_chinese_traditional": "จีน (ดั้งเดิม)", "seed_language_chinese_traditional": "จีน (ดั้งเดิม)",
"ascending": "จากน้อยไปมาก",
"descending": "ลงมา",
"dfx_option_description": "ซื้อ crypto ด้วย EUR และ CHF สูงถึง 990€ โดยไม่มี KYC เพิ่มเติม สำหรับลูกค้ารายย่อยและลูกค้าองค์กรในยุโรป", "dfx_option_description": "ซื้อ crypto ด้วย EUR และ CHF สูงถึง 990€ โดยไม่มี KYC เพิ่มเติม สำหรับลูกค้ารายย่อยและลูกค้าองค์กรในยุโรป",
"polygonscan_history": "ประวัติ PolygonScan", "polygonscan_history": "ประวัติ PolygonScan",
"wallet_seed_legacy": "เมล็ดกระเป๋าเงินมรดก" "wallet_seed_legacy": "เมล็ดกระเป๋าเงินมรดก",
"custom_drag": "กำหนดเอง (ค้างและลาก)",
"switchToEVMCompatibleWallet": "โปรดเปลี่ยนไปใช้กระเป๋าเงินที่รองรับ EVM แล้วลองอีกครั้ง (Ethereum, Polygon)"
} }

View file

@ -726,6 +726,9 @@
"require_for_exchanges_to_external_wallets": "Kinakailangan para sa mga palitan sa mga panlabas na wallet", "require_for_exchanges_to_external_wallets": "Kinakailangan para sa mga palitan sa mga panlabas na wallet",
"camera_permission_is_required": "Kinakailangan ang pahintulot sa camera.\nMangyaring paganahin ito mula sa mga setting ng app.", "camera_permission_is_required": "Kinakailangan ang pahintulot sa camera.\nMangyaring paganahin ito mula sa mga setting ng app.",
"switchToETHWallet": "Mangyaring lumipat sa isang Ethereum wallet at subukang muli", "switchToETHWallet": "Mangyaring lumipat sa isang Ethereum wallet at subukang muli",
"order_by": "Iniutos ni",
"creation_date": "Petsa ng paglikha",
"group_by_type": "Pangkat ayon sa uri",
"importNFTs": "Mag-import ng mga NFT", "importNFTs": "Mag-import ng mga NFT",
"noNFTYet": "Wala pang NFT", "noNFTYet": "Wala pang NFT",
"address": "Address", "address": "Address",
@ -744,7 +747,11 @@
"seed_language_czech": "Czech", "seed_language_czech": "Czech",
"seed_language_korean": "Korean", "seed_language_korean": "Korean",
"seed_language_chinese_traditional": "Intsik (tradisyonal)", "seed_language_chinese_traditional": "Intsik (tradisyonal)",
"ascending": "Umakyat",
"descending": "Pababang",
"dfx_option_description": "Bumili ng crypto gamit ang EUR at CHF. Hanggang 990€ nang walang karagdagang KYC. Para sa retail at corporate na mga customer sa Europe", "dfx_option_description": "Bumili ng crypto gamit ang EUR at CHF. Hanggang 990€ nang walang karagdagang KYC. Para sa retail at corporate na mga customer sa Europe",
"polygonscan_history": "Kasaysayan ng PolygonScan", "polygonscan_history": "Kasaysayan ng PolygonScan",
"wallet_seed_legacy": "Legacy wallet seed" "wallet_seed_legacy": "Legacy wallet seed",
"custom_drag": "Pasadyang (hawakan at i -drag)",
"switchToEVMCompatibleWallet": "Mangyaring lumipat sa isang EVM compatible na wallet at subukang muli (Ethereum, Polygon)"
} }

View file

@ -729,6 +729,9 @@
"require_for_exchanges_to_external_wallets": "Harici cüzdanlara geçiş yapılmasını zorunlu kılın", "require_for_exchanges_to_external_wallets": "Harici cüzdanlara geçiş yapılmasını zorunlu kılın",
"camera_permission_is_required": "Kamera izni gereklidir.\nLütfen uygulama ayarlarından etkinleştirin.", "camera_permission_is_required": "Kamera izni gereklidir.\nLütfen uygulama ayarlarından etkinleştirin.",
"switchToETHWallet": "Lütfen bir Ethereum cüzdanına geçin ve tekrar deneyin", "switchToETHWallet": "Lütfen bir Ethereum cüzdanına geçin ve tekrar deneyin",
"order_by": "Tarafından sipariş",
"creation_date": "Oluşturulma tarihi",
"group_by_type": "Türüne göre grup",
"importNFTs": "NFT'leri içe aktar", "importNFTs": "NFT'leri içe aktar",
"noNFTYet": "Henüz NFT yok", "noNFTYet": "Henüz NFT yok",
"address": "Adres", "address": "Adres",
@ -748,7 +751,11 @@
"seed_language_czech": "Çek", "seed_language_czech": "Çek",
"seed_language_korean": "Koreli", "seed_language_korean": "Koreli",
"seed_language_chinese_traditional": "Çin geleneği)", "seed_language_chinese_traditional": "Çin geleneği)",
"ascending": "Yükselen",
"descending": "Azalan",
"dfx_option_description": "EUR ve CHF ile kripto satın alın. Ek KYC olmadan 990 €'ya kadar. Avrupa'daki perakende ve kurumsal müşteriler için", "dfx_option_description": "EUR ve CHF ile kripto satın alın. Ek KYC olmadan 990 €'ya kadar. Avrupa'daki perakende ve kurumsal müşteriler için",
"polygonscan_history": "PolygonScan geçmişi", "polygonscan_history": "PolygonScan geçmişi",
"wallet_seed_legacy": "Eski cüzdan tohumu" "wallet_seed_legacy": "Eski cüzdan tohumu",
"custom_drag": "Özel (Bekle ve Sürükle)",
"switchToEVMCompatibleWallet": "Lütfen EVM uyumlu bir cüzdana geçin ve tekrar deneyin (Ethereum, Polygon)"
} }

View file

@ -731,6 +731,9 @@
"require_for_exchanges_to_external_wallets": "Потрібен для обміну на зовнішні гаманці", "require_for_exchanges_to_external_wallets": "Потрібен для обміну на зовнішні гаманці",
"camera_permission_is_required": "Потрібен дозвіл камери.\nУвімкніть його в налаштуваннях програми.", "camera_permission_is_required": "Потрібен дозвіл камери.\nУвімкніть його в налаштуваннях програми.",
"switchToETHWallet": "Перейдіть на гаманець Ethereum і повторіть спробу", "switchToETHWallet": "Перейдіть на гаманець Ethereum і повторіть спробу",
"order_by": "Сортувати за",
"creation_date": "Дата створення",
"group_by_type": "Група за типом",
"importNFTs": "Імпорт NFT", "importNFTs": "Імпорт NFT",
"noNFTYet": "NFT ще немає", "noNFTYet": "NFT ще немає",
"address": "Адреса", "address": "Адреса",
@ -749,8 +752,12 @@
"seedtype_polyseed": "Полісей (16 слів)", "seedtype_polyseed": "Полісей (16 слів)",
"seed_language_czech": "Чеський", "seed_language_czech": "Чеський",
"seed_language_korean": "Корейський", "seed_language_korean": "Корейський",
"ascending": "Висхід",
"descending": "Низхідний",
"dfx_option_description": "Купуйте криптовалюту за EUR і CHF. До 990 євро без додаткового KYC. Для роздрібних і корпоративних клієнтів у Європі", "dfx_option_description": "Купуйте криптовалюту за EUR і CHF. До 990 євро без додаткового KYC. Для роздрібних і корпоративних клієнтів у Європі",
"seed_language_chinese_traditional": "Китайський (традиційний)", "seed_language_chinese_traditional": "Китайський (традиційний)",
"polygonscan_history": "Історія PolygonScan", "polygonscan_history": "Історія PolygonScan",
"wallet_seed_legacy": "Спадець насіння гаманця" "wallet_seed_legacy": "Спадець насіння гаманця",
"custom_drag": "На замовлення (утримуйте та перетягується)",
"switchToEVMCompatibleWallet": "Перейдіть на гаманець, сумісний з EVM, і повторіть спробу (Ethereum, Polygon)"
} }

View file

@ -723,6 +723,9 @@
"require_for_exchanges_to_external_wallets": "۔ﮯﮨ ﺕﺭﻭﺮﺿ ﯽﮐ ﮯﻟﺩﺎﺒﺗ ﮟﯿﻣ ﮮﻮﭩﺑ ﯽﻧﻭﺮﯿﺑ", "require_for_exchanges_to_external_wallets": "۔ﮯﮨ ﺕﺭﻭﺮﺿ ﯽﮐ ﮯﻟﺩﺎﺒﺗ ﮟﯿﻣ ﮮﻮﭩﺑ ﯽﻧﻭﺮﯿﺑ",
"camera_permission_is_required": "۔ﮯﮨ ﺭﺎﮐﺭﺩ ﺕﺯﺎﺟﺍ ﯽﮐ ﮮﺮﻤﯿﮐ", "camera_permission_is_required": "۔ﮯﮨ ﺭﺎﮐﺭﺩ ﺕﺯﺎﺟﺍ ﯽﮐ ﮮﺮﻤﯿﮐ",
"switchToETHWallet": "۔ﮟﯾﺮﮐ ﺶﺷﻮﮐ ﮦﺭﺎﺑﻭﺩ ﺭﻭﺍ ﮟﯾﺮﮐ ﭻﺋﻮﺳ ﺮﭘ ﭧﯿﻟﺍﻭ Ethereum ﻡﺮﮐ ﮦﺍﺮﺑ", "switchToETHWallet": "۔ﮟﯾﺮﮐ ﺶﺷﻮﮐ ﮦﺭﺎﺑﻭﺩ ﺭﻭﺍ ﮟﯾﺮﮐ ﭻﺋﻮﺳ ﺮﭘ ﭧﯿﻟﺍﻭ Ethereum ﻡﺮﮐ ﮦﺍﺮﺑ",
"order_by": "آرڈر بذریعہ",
"creation_date": "بنانے کی تاریخ",
"group_by_type": "قسم کے لحاظ سے گروپ",
"importNFTs": "NFTs ۔ﮟﯾﺮﮐ ﺪﻣﺁﺭﺩ", "importNFTs": "NFTs ۔ﮟﯾﺮﮐ ﺪﻣﺁﺭﺩ",
"noNFTYet": "۔ﮟﯿﮨ ﮟﯿﮩﻧ NFTs ﯽﺋﻮﮐ ﮏﺗ ﯽﮭﺑﺍ", "noNFTYet": "۔ﮟﯿﮨ ﮟﯿﮩﻧ NFTs ﯽﺋﻮﮐ ﮏﺗ ﯽﮭﺑﺍ",
"address": "ﮧﺘﭘ", "address": "ﮧﺘﭘ",
@ -742,7 +745,11 @@
"seed_language_czech": "چیک", "seed_language_czech": "چیک",
"seed_language_korean": "کورین", "seed_language_korean": "کورین",
"seed_language_chinese_traditional": "چینی (روایتی)", "seed_language_chinese_traditional": "چینی (روایتی)",
"ascending": "چڑھنے",
"descending": "اترتے ہوئے",
"dfx_option_description": "EUR ﺭﻭﺍ CHF ﯽﻓﺎﺿﺍ ۔ﮟﯾﺪﯾﺮﺧ ﻮﭩﭘﺮﮐ ﮫﺗﺎﺳ ﮯﮐ KYC ﮯﯿﻟ ﮯﮐ ﻦﯿﻓﺭﺎﺻ ﭧﯾﺭﻮﭘﺭﺎﮐ ﺭﻭﺍ ﮦﺩﺭﻮﺧ ﮟ", "dfx_option_description": "EUR ﺭﻭﺍ CHF ﯽﻓﺎﺿﺍ ۔ﮟﯾﺪﯾﺮﺧ ﻮﭩﭘﺮﮐ ﮫﺗﺎﺳ ﮯﮐ KYC ﮯﯿﻟ ﮯﮐ ﻦﯿﻓﺭﺎﺻ ﭧﯾﺭﻮﭘﺭﺎﮐ ﺭﻭﺍ ﮦﺩﺭﻮﺧ ﮟ",
"polygonscan_history": "ﺦﯾﺭﺎﺗ ﯽﮐ ﻦﯿﮑﺳﺍ ﻥﻮﮔ ﯽﻟﻮﭘ", "polygonscan_history": "ﺦﯾﺭﺎﺗ ﯽﮐ ﻦﯿﮑﺳﺍ ﻥﻮﮔ ﯽﻟﻮﭘ",
"wallet_seed_legacy": "میراثی پرس کا بیج" "wallet_seed_legacy": "میراثی پرس کا بیج",
"custom_drag": "کسٹم (ہولڈ اینڈ ڈریگ)",
"switchToEVMCompatibleWallet": "(Ethereum, Polygon) ﮟﯾﺮﮐ ﺶﺷﻮﮐ ﮦﺭﺎﺑﻭﺩ ﺭﻭﺍ ﮟﯾﺮﮐ ﭻﺋﻮﺳ ﺮﭘ ﭧﯿﻟﺍﻭ ﮯﻟﺍﻭ ﮯﻨﮭﮐﺭ ﺖﻘﺑﺎﻄﻣ "
} }

View file

@ -725,6 +725,9 @@
"require_for_exchanges_to_external_wallets": "Beere fun awọn paṣipaarọ si awọn apamọwọ ita", "require_for_exchanges_to_external_wallets": "Beere fun awọn paṣipaarọ si awọn apamọwọ ita",
"camera_permission_is_required": "A nilo igbanilaaye kamẹra.\nJọwọ jeki o lati app eto.", "camera_permission_is_required": "A nilo igbanilaaye kamẹra.\nJọwọ jeki o lati app eto.",
"switchToETHWallet": "Jọwọ yipada si apamọwọ Ethereum ki o tun gbiyanju lẹẹkansi", "switchToETHWallet": "Jọwọ yipada si apamọwọ Ethereum ki o tun gbiyanju lẹẹkansi",
"order_by": "Bere fun nipasẹ",
"creation_date": "Ọjọ ẹda",
"group_by_type": "Ẹgbẹ nipasẹ Iru",
"importNFTs": "Gbe awọn NFT wọle", "importNFTs": "Gbe awọn NFT wọle",
"noNFTYet": "Ko si awọn NFT sibẹsibẹ", "noNFTYet": "Ko si awọn NFT sibẹsibẹ",
"address": "Adirẹsi", "address": "Adirẹsi",
@ -744,7 +747,11 @@
"seed_language_czech": "Czech", "seed_language_czech": "Czech",
"seed_language_korean": "Ara ẹni", "seed_language_korean": "Ara ẹni",
"seed_language_chinese_traditional": "Kannada (ibile)", "seed_language_chinese_traditional": "Kannada (ibile)",
"ascending": "Goke",
"descending": "Sọkalẹ",
"dfx_option_description": "Ra crypto pẹlu EUR & CHF. Titi di 990 € laisi afikun KYC. Fun soobu ati awọn onibara ile-iṣẹ ni Yuroopu", "dfx_option_description": "Ra crypto pẹlu EUR & CHF. Titi di 990 € laisi afikun KYC. Fun soobu ati awọn onibara ile-iṣẹ ni Yuroopu",
"polygonscan_history": "PolygonScan itan", "polygonscan_history": "PolygonScan itan",
"wallet_seed_legacy": "Irugbin akole" "wallet_seed_legacy": "Irugbin akole",
"custom_drag": "Aṣa (mu ati fa)",
"switchToEVMCompatibleWallet": "Jọwọ yipada si apamọwọ ibaramu EVM ki o tun gbiyanju lẹẹkansi (Ethereum, Polygon)"
} }

View file

@ -730,6 +730,9 @@
"require_for_exchanges_to_external_wallets": "需要兑换到外部钱包", "require_for_exchanges_to_external_wallets": "需要兑换到外部钱包",
"camera_permission_is_required": "需要相机许可。\n请从应用程序设置中启用它。", "camera_permission_is_required": "需要相机许可。\n请从应用程序设置中启用它。",
"switchToETHWallet": "请切换到以太坊钱包并重试", "switchToETHWallet": "请切换到以太坊钱包并重试",
"order_by": "订购",
"creation_date": "创建日期",
"group_by_type": "按类型组",
"importNFTs": "导入 NFT", "importNFTs": "导入 NFT",
"noNFTYet": "还没有 NFT", "noNFTYet": "还没有 NFT",
"address": "地址", "address": "地址",
@ -749,7 +752,11 @@
"seed_language_czech": "捷克", "seed_language_czech": "捷克",
"seed_language_korean": "韩国人", "seed_language_korean": "韩国人",
"seed_language_chinese_traditional": "中国传统的)", "seed_language_chinese_traditional": "中国传统的)",
"ascending": "上升",
"descending": "下降",
"dfx_option_description": "用欧元和瑞士法郎购买加密货币。高达 990 欧元,无需额外 KYC。对于欧洲的零售和企业客户", "dfx_option_description": "用欧元和瑞士法郎购买加密货币。高达 990 欧元,无需额外 KYC。对于欧洲的零售和企业客户",
"polygonscan_history": "多边形扫描历史", "polygonscan_history": "多边形扫描历史",
"wallet_seed_legacy": "旧的钱包种子" "wallet_seed_legacy": "旧的钱包种子",
"custom_drag": "定制(保持和拖动)",
"switchToEVMCompatibleWallet": "请切换到 EVM 兼容钱包并重试以太坊、Polygon"
} }

View file

@ -15,15 +15,15 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_ANDROID_TYPE=$1 APP_ANDROID_TYPE=$1
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.8.0" MONERO_COM_VERSION="1.9.0"
MONERO_COM_BUILD_NUMBER=69 MONERO_COM_BUILD_NUMBER=71
MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_BUNDLE_ID="com.monero.app"
MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_PACKAGE="com.monero.app"
MONERO_COM_SCHEME="monero.com" MONERO_COM_SCHEME="monero.com"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.11.0" CAKEWALLET_VERSION="4.12.0"
CAKEWALLET_BUILD_NUMBER=184 CAKEWALLET_BUILD_NUMBER=187
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
CAKEWALLET_SCHEME="cakewallet" CAKEWALLET_SCHEME="cakewallet"

View file

@ -10,7 +10,7 @@ case $APP_ANDROID_TYPE in
CONFIG_ARGS="--monero" CONFIG_ARGS="--monero"
;; ;;
$CAKEWALLET) $CAKEWALLET)
CONFIG_ARGS="--monero --bitcoin --haven --ethereum --nano --bitcoinCash" CONFIG_ARGS="--monero --bitcoin --haven --ethereum --polygon --nano --bitcoinCash"
;; ;;
$HAVEN) $HAVEN)
CONFIG_ARGS="--haven" CONFIG_ARGS="--haven"

View file

@ -28,7 +28,7 @@ case $APP_IOS_TYPE in
CONFIG_ARGS="--monero" CONFIG_ARGS="--monero"
;; ;;
$CAKEWALLET) $CAKEWALLET)
CONFIG_ARGS="--monero --bitcoin --haven --ethereum --nano --bitcoinCash" CONFIG_ARGS="--monero --bitcoin --haven --ethereum --polygon --nano --bitcoinCash"
;; ;;
$HAVEN) $HAVEN)

View file

@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_IOS_TYPE=$1 APP_IOS_TYPE=$1
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.8.0" MONERO_COM_VERSION="1.9.0"
MONERO_COM_BUILD_NUMBER=67 MONERO_COM_BUILD_NUMBER=69
MONERO_COM_BUNDLE_ID="com.cakewallet.monero" MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.11.0" CAKEWALLET_VERSION="4.12.0"
CAKEWALLET_BUILD_NUMBER=202 CAKEWALLET_BUILD_NUMBER=205
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
HAVEN_NAME="Haven" HAVEN_NAME="Haven"

View file

@ -23,7 +23,7 @@ CONFIG_ARGS=""
case $APP_MACOS_TYPE in case $APP_MACOS_TYPE in
$CAKEWALLET) $CAKEWALLET)
CONFIG_ARGS="--monero --bitcoin --ethereum --nano --bitcoinCash";; #--haven CONFIG_ARGS="--monero --bitcoin --ethereum --polygon --nano --bitcoinCash";; #--haven
esac esac
cp -rf pubspec_description.yaml pubspec.yaml cp -rf pubspec_description.yaml pubspec.yaml

View file

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