mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-31 06:55:59 +00:00
Merge branch 'main' of https://github.com/cake-tech/cake_wallet into mweb
This commit is contained in:
commit
48217cbc6e
16 changed files with 306 additions and 197 deletions
|
@ -253,7 +253,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
static CryptoCurrency fromString(String name, {CryptoCurrency? walletCurrency}) {
|
||||
try {
|
||||
return CryptoCurrency.all.firstWhere((element) =>
|
||||
element.title.toLowerCase() == name &&
|
||||
element.title.toLowerCase() == name.toLowerCase() &&
|
||||
(element.tag == null ||
|
||||
element.tag == walletCurrency?.title ||
|
||||
element.tag == walletCurrency?.tag));
|
||||
|
|
|
@ -399,6 +399,7 @@ extern "C"
|
|||
return false;
|
||||
}
|
||||
|
||||
wallet->store(std::string(path));
|
||||
change_current_wallet(wallet);
|
||||
return true;
|
||||
}
|
||||
|
@ -464,6 +465,16 @@ extern "C"
|
|||
return strdup(get_current_wallet()->address(account_index, address_index).c_str());
|
||||
}
|
||||
|
||||
char *get_cache_attribute(char *name)
|
||||
{
|
||||
return strdup(get_current_wallet()->getCacheAttribute(std::string(name)).c_str());
|
||||
}
|
||||
|
||||
bool set_cache_attribute(char *name, char *value)
|
||||
{
|
||||
get_current_wallet()->setCacheAttribute(std::string(name), std::string(value));
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *seed()
|
||||
{
|
||||
|
|
|
@ -154,3 +154,7 @@ typedef freeze_coin = Void Function(Int32 index);
|
|||
typedef thaw_coin = Void Function(Int32 index);
|
||||
|
||||
typedef sign_message = Pointer<Utf8> Function(Pointer<Utf8> message, Pointer<Utf8> address);
|
||||
|
||||
typedef get_cache_attribute = Pointer<Utf8> Function(Pointer<Utf8> name);
|
||||
|
||||
typedef set_cache_attribute = Int8 Function(Pointer<Utf8> name, Pointer<Utf8> value);
|
||||
|
|
|
@ -154,3 +154,7 @@ typedef FreezeCoin = void Function(int);
|
|||
typedef ThawCoin = void Function(int);
|
||||
|
||||
typedef SignMessage = Pointer<Utf8> Function(Pointer<Utf8>, Pointer<Utf8>);
|
||||
|
||||
typedef GetCacheAttribute = Pointer<Utf8> Function(Pointer<Utf8>);
|
||||
|
||||
typedef SetCacheAttribute = int Function(Pointer<Utf8>, Pointer<Utf8>);
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:cw_monero/api/structs/ut8_box.dart';
|
||||
|
||||
import 'package:cw_monero/api/convert_utf8_to_string.dart';
|
||||
import 'package:cw_monero/api/signatures.dart';
|
||||
import 'package:cw_monero/api/types.dart';
|
||||
import 'package:cw_monero/api/monero_api.dart';
|
||||
import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
|
||||
import 'package:cw_monero/api/monero_api.dart';
|
||||
import 'package:cw_monero/api/signatures.dart';
|
||||
import 'package:cw_monero/api/structs/ut8_box.dart';
|
||||
import 'package:cw_monero/api/types.dart';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
int _boolToInt(bool value) => value ? 1 : 0;
|
||||
|
||||
final getFileNameNative = moneroApi
|
||||
.lookup<NativeFunction<get_filename>>('get_filename')
|
||||
.asFunction<GetFilename>();
|
||||
final getFileNameNative =
|
||||
moneroApi.lookup<NativeFunction<get_filename>>('get_filename').asFunction<GetFilename>();
|
||||
|
||||
final getSeedNative =
|
||||
moneroApi.lookup<NativeFunction<get_seed>>('seed').asFunction<GetSeed>();
|
||||
final getSeedNative = moneroApi.lookup<NativeFunction<get_seed>>('seed').asFunction<GetSeed>();
|
||||
|
||||
final getAddressNative = moneroApi
|
||||
.lookup<NativeFunction<get_address>>('get_address')
|
||||
.asFunction<GetAddress>();
|
||||
final getAddressNative =
|
||||
moneroApi.lookup<NativeFunction<get_address>>('get_address').asFunction<GetAddress>();
|
||||
|
||||
final getFullBalanceNative = moneroApi
|
||||
.lookup<NativeFunction<get_full_balanace>>('get_full_balance')
|
||||
|
@ -38,41 +36,34 @@ final getNodeHeightNative = moneroApi
|
|||
.lookup<NativeFunction<get_node_height>>('get_node_height')
|
||||
.asFunction<GetNodeHeight>();
|
||||
|
||||
final isConnectedNative = moneroApi
|
||||
.lookup<NativeFunction<is_connected>>('is_connected')
|
||||
.asFunction<IsConnected>();
|
||||
final isConnectedNative =
|
||||
moneroApi.lookup<NativeFunction<is_connected>>('is_connected').asFunction<IsConnected>();
|
||||
|
||||
final setupNodeNative = moneroApi
|
||||
.lookup<NativeFunction<setup_node>>('setup_node')
|
||||
.asFunction<SetupNode>();
|
||||
final setupNodeNative =
|
||||
moneroApi.lookup<NativeFunction<setup_node>>('setup_node').asFunction<SetupNode>();
|
||||
|
||||
final startRefreshNative = moneroApi
|
||||
.lookup<NativeFunction<start_refresh>>('start_refresh')
|
||||
.asFunction<StartRefresh>();
|
||||
final startRefreshNative =
|
||||
moneroApi.lookup<NativeFunction<start_refresh>>('start_refresh').asFunction<StartRefresh>();
|
||||
|
||||
final connecToNodeNative = moneroApi
|
||||
.lookup<NativeFunction<connect_to_node>>('connect_to_node')
|
||||
.asFunction<ConnectToNode>();
|
||||
|
||||
final setRefreshFromBlockHeightNative = moneroApi
|
||||
.lookup<NativeFunction<set_refresh_from_block_height>>(
|
||||
'set_refresh_from_block_height')
|
||||
.lookup<NativeFunction<set_refresh_from_block_height>>('set_refresh_from_block_height')
|
||||
.asFunction<SetRefreshFromBlockHeight>();
|
||||
|
||||
final setRecoveringFromSeedNative = moneroApi
|
||||
.lookup<NativeFunction<set_recovering_from_seed>>(
|
||||
'set_recovering_from_seed')
|
||||
.lookup<NativeFunction<set_recovering_from_seed>>('set_recovering_from_seed')
|
||||
.asFunction<SetRecoveringFromSeed>();
|
||||
|
||||
final storeNative =
|
||||
moneroApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
|
||||
final storeNative = moneroApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
|
||||
|
||||
final setPasswordNative =
|
||||
moneroApi.lookup<NativeFunction<set_password>>('set_password').asFunction<SetPassword>();
|
||||
|
||||
final setListenerNative = moneroApi
|
||||
.lookup<NativeFunction<set_listener>>('set_listener')
|
||||
.asFunction<SetListener>();
|
||||
final setListenerNative =
|
||||
moneroApi.lookup<NativeFunction<set_listener>>('set_listener').asFunction<SetListener>();
|
||||
|
||||
final getSyncingHeightNative = moneroApi
|
||||
.lookup<NativeFunction<get_syncing_height>>('get_syncing_height')
|
||||
|
@ -83,8 +74,7 @@ final isNeededToRefreshNative = moneroApi
|
|||
.asFunction<IsNeededToRefresh>();
|
||||
|
||||
final isNewTransactionExistNative = moneroApi
|
||||
.lookup<NativeFunction<is_new_transaction_exist>>(
|
||||
'is_new_transaction_exist')
|
||||
.lookup<NativeFunction<is_new_transaction_exist>>('is_new_transaction_exist')
|
||||
.asFunction<IsNewTransactionExist>();
|
||||
|
||||
final getSecretViewKeyNative = moneroApi
|
||||
|
@ -107,9 +97,8 @@ final closeCurrentWalletNative = moneroApi
|
|||
.lookup<NativeFunction<close_current_wallet>>('close_current_wallet')
|
||||
.asFunction<CloseCurrentWallet>();
|
||||
|
||||
final onStartupNative = moneroApi
|
||||
.lookup<NativeFunction<on_startup>>('on_startup')
|
||||
.asFunction<OnStartup>();
|
||||
final onStartupNative =
|
||||
moneroApi.lookup<NativeFunction<on_startup>>('on_startup').asFunction<OnStartup>();
|
||||
|
||||
final rescanBlockchainAsyncNative = moneroApi
|
||||
.lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain')
|
||||
|
@ -123,13 +112,19 @@ final setTrustedDaemonNative = moneroApi
|
|||
.lookup<NativeFunction<set_trusted_daemon>>('set_trusted_daemon')
|
||||
.asFunction<SetTrustedDaemon>();
|
||||
|
||||
final trustedDaemonNative = moneroApi
|
||||
.lookup<NativeFunction<trusted_daemon>>('trusted_daemon')
|
||||
.asFunction<TrustedDaemon>();
|
||||
final trustedDaemonNative =
|
||||
moneroApi.lookup<NativeFunction<trusted_daemon>>('trusted_daemon').asFunction<TrustedDaemon>();
|
||||
|
||||
final signMessageNative = moneroApi
|
||||
.lookup<NativeFunction<sign_message>>('sign_message')
|
||||
.asFunction<SignMessage>();
|
||||
final signMessageNative =
|
||||
moneroApi.lookup<NativeFunction<sign_message>>('sign_message').asFunction<SignMessage>();
|
||||
|
||||
final getCacheAttributeNative = moneroApi
|
||||
.lookup<NativeFunction<get_cache_attribute>>('get_cache_attribute')
|
||||
.asFunction<GetCacheAttribute>();
|
||||
|
||||
final setCacheAttributeNative = moneroApi
|
||||
.lookup<NativeFunction<set_cache_attribute>>('set_cache_attribute')
|
||||
.asFunction<SetCacheAttribute>();
|
||||
|
||||
int getSyncingHeight() => getSyncingHeightNative();
|
||||
|
||||
|
@ -144,11 +139,9 @@ String getSeed() => convertUTF8ToString(pointer: getSeedNative());
|
|||
String getAddress({int accountIndex = 0, int addressIndex = 0}) =>
|
||||
convertUTF8ToString(pointer: getAddressNative(accountIndex, addressIndex));
|
||||
|
||||
int getFullBalance({int accountIndex = 0}) =>
|
||||
getFullBalanceNative(accountIndex);
|
||||
int getFullBalance({int accountIndex = 0}) => getFullBalanceNative(accountIndex);
|
||||
|
||||
int getUnlockedBalance({int accountIndex = 0}) =>
|
||||
getUnlockedBalanceNative(accountIndex);
|
||||
int getUnlockedBalance({int accountIndex = 0}) => getUnlockedBalanceNative(accountIndex);
|
||||
|
||||
int getCurrentHeight() => getCurrentHeightNative();
|
||||
|
||||
|
@ -187,7 +180,7 @@ bool setupNodeSync(
|
|||
passwordPointer,
|
||||
_boolToInt(useSSL),
|
||||
_boolToInt(isLightWallet),
|
||||
socksProxyAddressPointer,
|
||||
socksProxyAddressPointer,
|
||||
errorMessagePointer) !=
|
||||
0;
|
||||
|
||||
|
@ -202,8 +195,7 @@ bool setupNodeSync(
|
|||
}
|
||||
|
||||
if (!isSetupNode) {
|
||||
throw SetupWalletException(
|
||||
message: convertUTF8ToString(pointer: errorMessagePointer));
|
||||
throw SetupWalletException(message: convertUTF8ToString(pointer: errorMessagePointer));
|
||||
}
|
||||
|
||||
return isSetupNode;
|
||||
|
@ -213,8 +205,7 @@ void startRefreshSync() => startRefreshNative();
|
|||
|
||||
Future<bool> connectToNode() async => connecToNodeNative() != 0;
|
||||
|
||||
void setRefreshFromBlockHeight({required int height}) =>
|
||||
setRefreshFromBlockHeightNative(height);
|
||||
void setRefreshFromBlockHeight({required int height}) => setRefreshFromBlockHeightNative(height);
|
||||
|
||||
void setRecoveringFromSeed({required bool isRecovery}) =>
|
||||
setRecoveringFromSeedNative(_boolToInt(isRecovery));
|
||||
|
@ -230,7 +221,7 @@ void setPasswordSync(String password) {
|
|||
final errorMessagePointer = calloc<Utf8Box>();
|
||||
final changed = setPasswordNative(passwordPointer, errorMessagePointer) != 0;
|
||||
calloc.free(passwordPointer);
|
||||
|
||||
|
||||
if (!changed) {
|
||||
final message = errorMessagePointer.ref.getValue();
|
||||
calloc.free(errorMessagePointer);
|
||||
|
@ -242,24 +233,19 @@ void setPasswordSync(String password) {
|
|||
|
||||
void closeCurrentWallet() => closeCurrentWalletNative();
|
||||
|
||||
String getSecretViewKey() =>
|
||||
convertUTF8ToString(pointer: getSecretViewKeyNative());
|
||||
String getSecretViewKey() => convertUTF8ToString(pointer: getSecretViewKeyNative());
|
||||
|
||||
String getPublicViewKey() =>
|
||||
convertUTF8ToString(pointer: getPublicViewKeyNative());
|
||||
String getPublicViewKey() => convertUTF8ToString(pointer: getPublicViewKeyNative());
|
||||
|
||||
String getSecretSpendKey() =>
|
||||
convertUTF8ToString(pointer: getSecretSpendKeyNative());
|
||||
String getSecretSpendKey() => convertUTF8ToString(pointer: getSecretSpendKeyNative());
|
||||
|
||||
String getPublicSpendKey() =>
|
||||
convertUTF8ToString(pointer: getPublicSpendKeyNative());
|
||||
String getPublicSpendKey() => convertUTF8ToString(pointer: getPublicSpendKeyNative());
|
||||
|
||||
class SyncListener {
|
||||
SyncListener(this.onNewBlock, this.onNewTransaction)
|
||||
: _cachedBlockchainHeight = 0,
|
||||
_lastKnownBlockHeight = 0,
|
||||
_initialSyncHeight = 0;
|
||||
|
||||
SyncListener(this.onNewBlock, this.onNewTransaction)
|
||||
: _cachedBlockchainHeight = 0,
|
||||
_lastKnownBlockHeight = 0,
|
||||
_initialSyncHeight = 0;
|
||||
|
||||
void Function(int, int, double) onNewBlock;
|
||||
void Function() onNewTransaction;
|
||||
|
@ -281,8 +267,7 @@ class SyncListener {
|
|||
_cachedBlockchainHeight = 0;
|
||||
_lastKnownBlockHeight = 0;
|
||||
_initialSyncHeight = 0;
|
||||
_updateSyncInfoTimer ??=
|
||||
Timer.periodic(Duration(milliseconds: 1200), (_) async {
|
||||
_updateSyncInfoTimer ??= Timer.periodic(Duration(milliseconds: 1200), (_) async {
|
||||
if (isNewTransactionExist()) {
|
||||
onNewTransaction();
|
||||
}
|
||||
|
@ -321,8 +306,8 @@ class SyncListener {
|
|||
void stop() => _updateSyncInfoTimer?.cancel();
|
||||
}
|
||||
|
||||
SyncListener setListeners(void Function(int, int, double) onNewBlock,
|
||||
void Function() onNewTransaction) {
|
||||
SyncListener setListeners(
|
||||
void Function(int, int, double) onNewBlock, void Function() onNewTransaction) {
|
||||
final listener = SyncListener(onNewBlock, onNewTransaction);
|
||||
setListenerNative();
|
||||
return listener;
|
||||
|
@ -364,7 +349,7 @@ Future<void> setupNode(
|
|||
bool isLightWallet = false}) =>
|
||||
compute<Map<String, Object?>, void>(_setupNodeSync, {
|
||||
'address': address,
|
||||
'login': login ,
|
||||
'login': login,
|
||||
'password': password,
|
||||
'useSSL': useSSL,
|
||||
'isLightWallet': isLightWallet,
|
||||
|
@ -397,3 +382,23 @@ String signMessage(String message, {String address = ""}) {
|
|||
|
||||
return signature;
|
||||
}
|
||||
|
||||
bool setCacheAttribute(String name, String value) {
|
||||
final namePointer = name.toNativeUtf8();
|
||||
final valuePointer = value.toNativeUtf8();
|
||||
|
||||
final isSet = setCacheAttributeNative(namePointer, valuePointer);
|
||||
calloc.free(namePointer);
|
||||
calloc.free(valuePointer);
|
||||
|
||||
return isSet == 1;
|
||||
}
|
||||
|
||||
String getCacheAttribute(String name) {
|
||||
final namePointer = name.toNativeUtf8();
|
||||
|
||||
final value = convertUTF8ToString(pointer: getCacheAttributeNative(namePointer));
|
||||
calloc.free(namePointer);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -19,30 +19,6 @@ class DefaultSPLTokens {
|
|||
mint: 'usdcsol',
|
||||
enabled: true,
|
||||
),
|
||||
SPLToken(
|
||||
name: 'Wrapped Ethereum (Sollet)',
|
||||
symbol: 'soETH',
|
||||
mintAddress: '2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk',
|
||||
decimal: 6,
|
||||
mint: 'soEth',
|
||||
iconPath: 'assets/images/eth_icon.png',
|
||||
),
|
||||
SPLToken(
|
||||
name: 'Wrapped SOL',
|
||||
symbol: 'WSOL',
|
||||
mintAddress: 'So11111111111111111111111111111111111111112',
|
||||
decimal: 9,
|
||||
mint: 'WSOL',
|
||||
iconPath: 'assets/images/sol_icon.png',
|
||||
),
|
||||
SPLToken(
|
||||
name: 'Wrapped Bitcoin (Sollet)',
|
||||
symbol: 'BTC',
|
||||
mintAddress: '9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E',
|
||||
decimal: 6,
|
||||
mint: 'btcsol',
|
||||
iconPath: 'assets/images/btc.png',
|
||||
),
|
||||
SPLToken(
|
||||
name: 'Bonk',
|
||||
symbol: 'Bonk',
|
||||
|
@ -50,21 +26,7 @@ class DefaultSPLTokens {
|
|||
decimal: 5,
|
||||
mint: 'Bonk',
|
||||
iconPath: 'assets/images/bonk_icon.png',
|
||||
),
|
||||
SPLToken(
|
||||
name: 'Helium Network Token',
|
||||
symbol: 'HNT',
|
||||
mintAddress: 'hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux',
|
||||
decimal: 8,
|
||||
mint: 'hnt',
|
||||
iconPath: 'assets/images/hnt_icon.png',
|
||||
),
|
||||
SPLToken(
|
||||
name: 'Pyth Network',
|
||||
symbol: 'PYTH',
|
||||
mintAddress: 'HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3',
|
||||
decimal: 6,
|
||||
mint: 'pyth',
|
||||
enabled: true,
|
||||
),
|
||||
SPLToken(
|
||||
name: 'Raydium',
|
||||
|
@ -73,6 +35,51 @@ class DefaultSPLTokens {
|
|||
decimal: 6,
|
||||
mint: 'ray',
|
||||
iconPath: 'assets/images/ray_icon.png',
|
||||
enabled: true,
|
||||
),
|
||||
SPLToken(
|
||||
name: 'Wrapped Ethereum (Sollet)',
|
||||
symbol: 'soETH',
|
||||
mintAddress: '2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk',
|
||||
decimal: 6,
|
||||
mint: 'soEth',
|
||||
iconPath: 'assets/images/eth_icon.png',
|
||||
enabled: false,
|
||||
),
|
||||
SPLToken(
|
||||
name: 'Wrapped SOL',
|
||||
symbol: 'WSOL',
|
||||
mintAddress: 'So11111111111111111111111111111111111111112',
|
||||
decimal: 9,
|
||||
mint: 'WSOL',
|
||||
iconPath: 'assets/images/sol_icon.png',
|
||||
enabled: false,
|
||||
),
|
||||
SPLToken(
|
||||
name: 'Wrapped Bitcoin (Sollet)',
|
||||
symbol: 'BTC',
|
||||
mintAddress: '9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E',
|
||||
decimal: 6,
|
||||
mint: 'btcsol',
|
||||
iconPath: 'assets/images/btc.png',
|
||||
enabled: false,
|
||||
),
|
||||
SPLToken(
|
||||
name: 'Helium Network Token',
|
||||
symbol: 'HNT',
|
||||
mintAddress: 'hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux',
|
||||
decimal: 8,
|
||||
mint: 'hnt',
|
||||
iconPath: 'assets/images/hnt_icon.png',
|
||||
enabled: false,
|
||||
),
|
||||
SPLToken(
|
||||
name: 'Pyth Network',
|
||||
symbol: 'PYTH',
|
||||
mintAddress: 'HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3',
|
||||
decimal: 6,
|
||||
mint: 'pyth',
|
||||
enabled: false,
|
||||
),
|
||||
SPLToken(
|
||||
name: 'GMT',
|
||||
|
@ -81,6 +88,7 @@ class DefaultSPLTokens {
|
|||
decimal: 6,
|
||||
mint: 'ray',
|
||||
iconPath: 'assets/images/gmt_icon.png',
|
||||
enabled: false,
|
||||
),
|
||||
SPLToken(
|
||||
name: 'AvocadoCoin',
|
||||
|
@ -89,6 +97,7 @@ class DefaultSPLTokens {
|
|||
decimal: 8,
|
||||
mint: 'avdo',
|
||||
iconPath: 'assets/images/avdo_icon.png',
|
||||
enabled: false,
|
||||
),
|
||||
];
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ class SolanaBalance extends Balance {
|
|||
|
||||
String _balanceFormatted() {
|
||||
String stringBalance = balance.toString();
|
||||
if (stringBalance.toString().length >= 6) {
|
||||
stringBalance = stringBalance.substring(0, 6);
|
||||
if (stringBalance.toString().length >= 12) {
|
||||
stringBalance = stringBalance.substring(0, 12);
|
||||
}
|
||||
return stringBalance;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ class WalletCreationService {
|
|||
checkIfExists(credentials.name);
|
||||
final password = generateWalletPassword();
|
||||
credentials.password = password;
|
||||
if (type == WalletType.bitcoinCash || type == WalletType.ethereum) {
|
||||
if (_hasSeedPhraseLengthOption) {
|
||||
credentials.seedPhraseLength = settingsStore.seedPhraseLength.value;
|
||||
}
|
||||
await keyService.saveWalletPassword(password: password, walletName: credentials.name);
|
||||
|
@ -72,6 +72,25 @@ class WalletCreationService {
|
|||
return wallet;
|
||||
}
|
||||
|
||||
bool get _hasSeedPhraseLengthOption {
|
||||
switch (type) {
|
||||
case WalletType.ethereum:
|
||||
case WalletType.bitcoinCash:
|
||||
case WalletType.polygon:
|
||||
case WalletType.solana:
|
||||
case WalletType.tron:
|
||||
return true;
|
||||
case WalletType.monero:
|
||||
case WalletType.none:
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.haven:
|
||||
case WalletType.nano:
|
||||
case WalletType.banano:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<WalletBase> restoreFromKeys(WalletCredentials credentials, {bool? isTestnet}) async {
|
||||
checkIfExists(credentials.name);
|
||||
final password = generateWalletPassword();
|
||||
|
|
14
lib/di.dart
14
lib/di.dart
|
@ -14,6 +14,7 @@ import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
|||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/core/backup_service.dart';
|
||||
import 'package:cake_wallet/core/key_service.dart';
|
||||
import 'package:cake_wallet/core/secure_storage.dart';
|
||||
import 'package:cake_wallet/core/wallet_connect/wallet_connect_key_service.dart';
|
||||
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
|
||||
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
|
||||
|
@ -26,10 +27,6 @@ import 'package:cake_wallet/entities/contact.dart';
|
|||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
|
||||
import 'package:cw_core/receive_page_option.dart';
|
||||
import 'package:cake_wallet/entities/qr_view_data.dart';
|
||||
import 'package:cake_wallet/entities/template.dart';
|
||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||
|
@ -124,6 +121,7 @@ import 'package:cake_wallet/src/screens/support/support_page.dart';
|
|||
import 'package:cake_wallet/src/screens/support_chat/support_chat_page.dart';
|
||||
import 'package:cake_wallet/src/screens/support_other_links/support_other_links_page.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
|
||||
|
@ -147,6 +145,7 @@ import 'package:cake_wallet/store/templates/send_template_store.dart';
|
|||
import 'package:cake_wallet/store/wallet_list_store.dart';
|
||||
import 'package:cake_wallet/store/yat/yat_store.dart';
|
||||
import 'package:cake_wallet/themes/theme_list.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
|
@ -179,6 +178,7 @@ import 'package:cake_wallet/view_model/ionia/ionia_gift_card_details_view_model.
|
|||
import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_payment_status_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart';
|
||||
|
@ -222,6 +222,7 @@ import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
|
|||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/nano_account.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/receive_page_option.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
|
@ -233,7 +234,6 @@ import 'package:get_it/get_it.dart';
|
|||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cake_wallet/core/secure_storage.dart';
|
||||
|
||||
import 'buy/dfx/dfx_buy_provider.dart';
|
||||
import 'core/totp_request_details.dart';
|
||||
|
@ -795,8 +795,8 @@ Future<void> setup({
|
|||
|
||||
getIt.registerFactory(() => ConnectionSyncPage(getIt.get<DashboardViewModel>()));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(), getIt.get<AuthService>()));
|
||||
getIt.registerFactory(() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(),
|
||||
getIt.get<AuthService>(), getIt.get<AppStore>().wallet!.isHardwareWallet));
|
||||
|
||||
getIt.registerFactory(() => PrivacyPage(getIt.get<PrivacySettingsViewModel>()));
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ class ContactPage extends BasePage {
|
|||
final TextEditingController _nameController;
|
||||
final TextEditingController _currencyTypeController;
|
||||
final TextEditingController _addressController;
|
||||
bool _isEffectsApplied = false;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
|
@ -53,15 +54,7 @@ class ContactPage extends BasePage {
|
|||
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
|
||||
height: 8);
|
||||
|
||||
reaction((_) => contactViewModel.state, (ExecutionState state) {
|
||||
if (state is FailureState) {
|
||||
_onContactSavingFailure(context, state.error);
|
||||
}
|
||||
|
||||
if (state is ExecutedSuccessfullyState) {
|
||||
_onContactSavedSuccessfully(context);
|
||||
}
|
||||
});
|
||||
_setEffects(context);
|
||||
|
||||
return Observer(
|
||||
builder: (_) => ScrollableWithBottomSection(
|
||||
|
@ -177,4 +170,22 @@ class ContactPage extends BasePage {
|
|||
|
||||
void _onContactSavedSuccessfully(BuildContext context) =>
|
||||
Navigator.of(context).pop();
|
||||
|
||||
void _setEffects(BuildContext context) {
|
||||
if (_isEffectsApplied) {
|
||||
return;
|
||||
}
|
||||
|
||||
_isEffectsApplied = true;
|
||||
|
||||
reaction((_) => contactViewModel.state, (ExecutionState state) {
|
||||
if (state is FailureState) {
|
||||
_onContactSavingFailure(context, state.error);
|
||||
}
|
||||
|
||||
if (state is ExecutedSuccessfullyState) {
|
||||
_onContactSavedSuccessfully(context);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart'
|
|||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
|
||||
class DashboardPage extends StatelessWidget {
|
||||
class DashboardPage extends StatefulWidget {
|
||||
DashboardPage({
|
||||
required this.bottomSheetService,
|
||||
required this.balancePage,
|
||||
|
@ -50,43 +50,71 @@ class DashboardPage extends StatelessWidget {
|
|||
final WalletAddressListViewModel addressListViewModel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final screenHeight = MediaQuery.of(context).size.height;
|
||||
return Scaffold(
|
||||
body: Builder(
|
||||
builder: (_) {
|
||||
final dashboardPageView = RefreshIndicator(
|
||||
displacement: screenHeight * 0.1,
|
||||
onRefresh: () async => await dashboardViewModel.refreshDashboard(),
|
||||
child: SingleChildScrollView(
|
||||
physics: AlwaysScrollableScrollPhysics(),
|
||||
child: Container(
|
||||
height: screenHeight,
|
||||
child: _DashboardPageView(
|
||||
balancePage: balancePage,
|
||||
bottomSheetService: bottomSheetService,
|
||||
dashboardViewModel: dashboardViewModel,
|
||||
addressListViewModel: addressListViewModel,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
State<DashboardPage> createState() => _DashboardPageState();
|
||||
}
|
||||
|
||||
if (DeviceInfo.instance.isDesktop) {
|
||||
if (responsiveLayoutUtil.screenWidth >
|
||||
ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) {
|
||||
return getIt.get<DesktopSidebarWrapper>();
|
||||
} else {
|
||||
return dashboardPageView;
|
||||
}
|
||||
} else if (responsiveLayoutUtil.shouldRenderMobileUI) {
|
||||
return dashboardPageView;
|
||||
} else {
|
||||
return getIt.get<DesktopSidebarWrapper>();
|
||||
}
|
||||
},
|
||||
class _DashboardPageState extends State<DashboardPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
bool isMobileLayout =
|
||||
responsiveLayoutUtil.screenWidth < ResponsiveLayoutUtilBase.kMobileThreshold;
|
||||
|
||||
reaction((_) => responsiveLayoutUtil.screenWidth, (screenWidth) {
|
||||
// Check if it was previously in mobile layout, and now changing to desktop
|
||||
if (isMobileLayout &&
|
||||
screenWidth > ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) {
|
||||
setState(() {
|
||||
isMobileLayout = false;
|
||||
});
|
||||
}
|
||||
|
||||
// Check if it was previously in desktop layout, and now changing to mobile
|
||||
if (!isMobileLayout &&
|
||||
screenWidth <= ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) {
|
||||
setState(() {
|
||||
isMobileLayout = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget dashboardChild;
|
||||
|
||||
final dashboardPageView = RefreshIndicator(
|
||||
displacement: responsiveLayoutUtil.screenHeight * 0.1,
|
||||
onRefresh: () async => await widget.dashboardViewModel.refreshDashboard(),
|
||||
child: SingleChildScrollView(
|
||||
physics: AlwaysScrollableScrollPhysics(),
|
||||
child: Container(
|
||||
height: responsiveLayoutUtil.screenHeight,
|
||||
child: _DashboardPageView(
|
||||
balancePage: widget.balancePage,
|
||||
bottomSheetService: widget.bottomSheetService,
|
||||
dashboardViewModel: widget.dashboardViewModel,
|
||||
addressListViewModel: widget.addressListViewModel,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (DeviceInfo.instance.isDesktop) {
|
||||
if (responsiveLayoutUtil.screenWidth >
|
||||
ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) {
|
||||
dashboardChild = getIt.get<DesktopSidebarWrapper>();
|
||||
} else {
|
||||
dashboardChild = dashboardPageView;
|
||||
}
|
||||
} else if (responsiveLayoutUtil.shouldRenderMobileUI) {
|
||||
dashboardChild = dashboardPageView;
|
||||
} else {
|
||||
dashboardChild = getIt.get<DesktopSidebarWrapper>();
|
||||
}
|
||||
|
||||
return Scaffold(body: dashboardChild);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,14 +9,13 @@ import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.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_switcher_cell.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class SecurityBackupPage extends BasePage {
|
||||
SecurityBackupPage(this._securitySettingsViewModel, this._authService);
|
||||
SecurityBackupPage(this._securitySettingsViewModel, this._authService, [this._isHardwareWallet = false]);
|
||||
|
||||
final AuthService _authService;
|
||||
|
||||
|
@ -25,20 +24,23 @@ class SecurityBackupPage extends BasePage {
|
|||
|
||||
final SecuritySettingsViewModel _securitySettingsViewModel;
|
||||
|
||||
final bool _isHardwareWallet;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.show_keys,
|
||||
handler: (_) => _authService.authenticateAction(
|
||||
context,
|
||||
route: Routes.showKeys,
|
||||
conditionToDetermineIfToUse2FA: _securitySettingsViewModel
|
||||
.shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
|
||||
if (!_isHardwareWallet)
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.show_keys,
|
||||
handler: (_) => _authService.authenticateAction(
|
||||
context,
|
||||
route: Routes.showKeys,
|
||||
conditionToDetermineIfToUse2FA:
|
||||
_securitySettingsViewModel.shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
|
||||
),
|
||||
),
|
||||
),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.create_backup,
|
||||
handler: (_) => _authService.authenticateAction(
|
||||
|
|
|
@ -6,7 +6,7 @@ part 'responsive_layout_util.g.dart';
|
|||
class _ResponsiveLayoutUtil = ResponsiveLayoutUtilBase with _$_ResponsiveLayoutUtil;
|
||||
|
||||
abstract class ResponsiveLayoutUtilBase with Store, WidgetsBindingObserver {
|
||||
static const double _kMobileThreshold = 550;
|
||||
static const double kMobileThreshold = 550;
|
||||
static const double kDesktopMaxWidthConstraint = 400;
|
||||
static const double kDesktopMaxDashBoardWidthConstraint = 900;
|
||||
static const double kPopupWidth = 400;
|
||||
|
@ -42,13 +42,13 @@ abstract class ResponsiveLayoutUtilBase with Store, WidgetsBindingObserver {
|
|||
|
||||
@computed
|
||||
bool get shouldRenderMobileUI {
|
||||
return (screenWidth <= _kMobileThreshold) ||
|
||||
return (screenWidth <= kMobileThreshold) ||
|
||||
(orientation == Orientation.portrait && screenWidth < screenHeight) ||
|
||||
(orientation == Orientation.landscape && screenWidth < screenHeight);
|
||||
}
|
||||
|
||||
bool get shouldRenderTabletUI {
|
||||
return screenWidth > _kMobileThreshold && screenWidth < kDesktopMaxDashBoardWidthConstraint;
|
||||
return screenWidth > kMobileThreshold && screenWidth < kDesktopMaxDashBoardWidthConstraint;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -535,24 +535,29 @@ abstract class DashboardViewModelBase with Store {
|
|||
|
||||
Future<ServicesResponse> getServicesStatus() async {
|
||||
try {
|
||||
final res = await http.get(Uri.parse("https://service-api.cakewallet.com/v1/active-notices"));
|
||||
if (isEnabledBulletinAction) {
|
||||
final res = await http.get(Uri.parse("https://service-api.cakewallet.com/v1/active-notices"));
|
||||
|
||||
if (res.statusCode < 200 || res.statusCode >= 300) {
|
||||
throw res.body;
|
||||
if (res.statusCode < 200 || res.statusCode >= 300) {
|
||||
throw res.body;
|
||||
}
|
||||
|
||||
final oldSha = sharedPreferences.getString(PreferencesKey.serviceStatusShaKey);
|
||||
|
||||
final hash = await Cryptography.instance.sha256().hash(utf8.encode(res.body));
|
||||
final currentSha = bytesToHex(hash.bytes);
|
||||
|
||||
final hasUpdates = oldSha != currentSha;
|
||||
|
||||
return ServicesResponse.fromJson(
|
||||
json.decode(res.body) as Map<String, dynamic>,
|
||||
hasUpdates,
|
||||
currentSha,
|
||||
);
|
||||
}
|
||||
|
||||
final oldSha = sharedPreferences.getString(PreferencesKey.serviceStatusShaKey);
|
||||
|
||||
final hash = await Cryptography.instance.sha256().hash(utf8.encode(res.body));
|
||||
final currentSha = bytesToHex(hash.bytes);
|
||||
|
||||
final hasUpdates = oldSha != currentSha;
|
||||
|
||||
return ServicesResponse.fromJson(
|
||||
json.decode(res.body) as Map<String, dynamic>,
|
||||
hasUpdates,
|
||||
currentSha,
|
||||
);
|
||||
else {
|
||||
return ServicesResponse([], false, '');
|
||||
}
|
||||
} catch (_) {
|
||||
return ServicesResponse([], false, '');
|
||||
}
|
||||
|
|
|
@ -154,11 +154,11 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
|||
ChangeNowExchangeProvider(settingsStore: _settingsStore),
|
||||
SideShiftExchangeProvider(),
|
||||
SimpleSwapExchangeProvider(),
|
||||
TrocadorExchangeProvider(
|
||||
useTorOnly: _useTorOnly, providerStates: _settingsStore.trocadorProviderStates),
|
||||
ThorChainExchangeProvider(tradesStore: trades),
|
||||
if (FeatureFlag.isExolixEnabled) ExolixExchangeProvider(),
|
||||
QuantexExchangeProvider(),
|
||||
TrocadorExchangeProvider(
|
||||
useTorOnly: _useTorOnly, providerStates: _settingsStore.trocadorProviderStates),
|
||||
];
|
||||
|
||||
@observable
|
||||
|
|
|
@ -139,8 +139,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
|||
String get pendingTransactionFeeFiatAmount {
|
||||
try {
|
||||
if (pendingTransaction != null) {
|
||||
final currency =
|
||||
isEVMCompatibleChain(walletType) ? wallet.currency : selectedCryptoCurrency;
|
||||
final currency = pendingTransactionFeeCurrency(walletType);
|
||||
final fiat = calculateFiatAmount(
|
||||
price: _fiatConversationStore.prices[currency]!,
|
||||
cryptoAmount: pendingTransaction!.feeFormatted);
|
||||
|
@ -153,6 +152,18 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
|||
}
|
||||
}
|
||||
|
||||
CryptoCurrency pendingTransactionFeeCurrency(WalletType type) {
|
||||
switch (type) {
|
||||
case WalletType.ethereum:
|
||||
case WalletType.polygon:
|
||||
case WalletType.tron:
|
||||
case WalletType.solana:
|
||||
return wallet.currency;
|
||||
default:
|
||||
return selectedCryptoCurrency;
|
||||
}
|
||||
}
|
||||
|
||||
FiatCurrency get fiat => _settingsStore.fiatCurrency;
|
||||
|
||||
TransactionPriority get transactionPriority {
|
||||
|
|
Loading…
Reference in a new issue