mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-18 05:51:34 +02:00
The big one. Touches 760+ files. Locks in the user's decision to break import-line compatibility with upstream cake-tech/cake_wallet in exchange for a binary named hash_wallet on every platform. Changes: - pubspec_description.yaml: project name cake_wallet -> hash_wallet - 762 Dart files: every 'package:cake_wallet/...' import rewritten to 'package:hash_wallet/...' (lib/, cw_*/lib/, tool/, test/, integration_test/) - linux/CMakeLists.txt: BINARY_NAME cake_wallet -> hash_wallet - windows/CMakeLists.txt: project + BINARY_NAME (CakeWallet -> HashWallet) - windows/runner/Runner.rc: company / file / product strings to Hash Wallet + Such Software LLC copyright - macos/Runner.xcodeproj/project_base.pbxproj: cake_wallet_new.app refs -> hash_wallet.app (macOS output bundle name) - com.suchsoftware.HashWallet.yml (Flatpak): all binary path refs cake_wallet -> hash_wallet (e.g. /app/hash_wallet/hash_wallet) - linux/com.suchsoftware.HashWallet.desktop: Exec=hash_wallet - scripts/android/copy_monero_deps.sh: CW_DIR target path - configure_hash_wallet.sh: error message typo (old filename) INTENTIONALLY UNCHANGED: - cw_* subpackage names (cw_core, cw_bitcoin, cw_wownero, etc.) — they remain as the historical 'cake wallet' naming; renaming them would cascade through every sub-package's internal structure - Method channel name 'com.cake_wallet/native_utils' in iOS/macOS/Android AppDelegates and MainActivity — it's a string identifier that has to match the Dart side exactly. Renaming requires both-sides change; it's internal-only and not user-visible. - ghcr.io/cake-tech/cake_wallet:debian13-... docker image references in build scripts — that's Cake Labs' published image we use as the build environment, not ours. User data directory now follows the new binary name: ~/.local/share/hash_wallet/ (was ~/.local/share/cake_wallet/) ~/.config/hash_wallet/ (was ~/.config/cake_wallet/) Existing users on the old name will need migration if any exist.
289 lines
8.7 KiB
Dart
289 lines
8.7 KiB
Dart
import 'package:hash_wallet/core/execution_state.dart';
|
|
import 'package:hash_wallet/core/utilities.dart';
|
|
import 'package:hash_wallet/entities/calculate_fiat_amount.dart';
|
|
import 'package:hash_wallet/entities/fiat_currency.dart';
|
|
import 'package:hash_wallet/evm/evm.dart';
|
|
import 'package:hash_wallet/store/app_store.dart';
|
|
import 'package:hash_wallet/store/dashboard/fiat_conversion_store.dart';
|
|
import 'package:hash_wallet/store/settings_store.dart';
|
|
import 'package:hash_wallet/view_model/dashboard/balance_view_model.dart';
|
|
import 'package:hash_wallet/view_model/hardware_wallet/hardware_wallet_view_model.dart';
|
|
import 'package:hash_wallet/view_model/send/send_view_model_state.dart';
|
|
import 'package:cw_core/crypto_currency.dart';
|
|
import 'package:cw_core/parse_fixed.dart';
|
|
import 'package:cw_core/pending_transaction.dart';
|
|
import 'package:cw_core/wallet_base.dart';
|
|
import 'package:mobx/mobx.dart';
|
|
|
|
part 'deuro_view_model.g.dart';
|
|
|
|
class DEuroViewModel = DEuroViewModelBase with _$DEuroViewModel;
|
|
|
|
abstract class DEuroViewModelBase with Store {
|
|
final AppStore _appStore;
|
|
|
|
static BigInt get MIN_ACCRUED_INTEREST => BigInt.parse("1000000000000");
|
|
|
|
DEuroViewModelBase(
|
|
this._appStore, this.balanceViewModel, this._settingsStore, this._fiatConversationStore,
|
|
[this.hardwareWalletViewModel]) {
|
|
reloadInterestRate();
|
|
reloadSavingsUserData();
|
|
}
|
|
|
|
final BalanceViewModel balanceViewModel;
|
|
final HardwareWalletViewModel? hardwareWalletViewModel;
|
|
final SettingsStore _settingsStore;
|
|
final FiatConversionStore _fiatConversationStore;
|
|
|
|
WalletBase get wallet => this._appStore.wallet!;
|
|
|
|
@computed
|
|
bool get isFiatDisabled => balanceViewModel.isFiatDisabled;
|
|
|
|
@computed
|
|
bool get isFistTime => _settingsStore.shouldShowDEuroDisclaimer;
|
|
|
|
@action
|
|
void acceptDisclaimer() => _settingsStore.shouldShowDEuroDisclaimer = false;
|
|
|
|
FiatCurrency get fiat => _settingsStore.fiatCurrency;
|
|
|
|
@computed
|
|
String get pendingTransactionFiatAmountFormatted {
|
|
final amount = transaction == null ? '0.00' : _getDEuroFiatAmount(transaction!.amountFormatted);
|
|
return isFiatDisabled ? '' : '$amount ${fiat.title}';
|
|
}
|
|
|
|
@computed
|
|
String get pendingTransactionFeeFiatAmountFormatted {
|
|
var amount = '0.00';
|
|
try {
|
|
if (transaction != null) {
|
|
final feeCurrency = CryptoCurrency.eth;
|
|
amount = calculateFiatAmount(
|
|
price: _fiatConversationStore.prices[feeCurrency]!,
|
|
cryptoAmount: transaction!.feeFormattedValue,
|
|
);
|
|
}
|
|
} catch (_) {}
|
|
return isFiatDisabled ? '' : '$amount ${fiat.title}';
|
|
}
|
|
|
|
@computed
|
|
String get accountBalanceFormated {
|
|
final dEuroKey = balanceViewModel.balances.keys
|
|
.firstWhereOrNull((e) => e.title == CryptoCurrency.deuro.title);
|
|
if (dEuroKey == null) return '0.00';
|
|
return balanceViewModel.balances[dEuroKey]?.availableBalance ?? '0.00';
|
|
}
|
|
|
|
@observable
|
|
BigInt savingsBalance = BigInt.zero;
|
|
|
|
@computed
|
|
String get savingsBalanceFormated =>
|
|
evm!.formatterEVMAmountToDouble(amount: savingsBalance).toStringAsFixed(6);
|
|
|
|
@computed
|
|
String get fiatSavingsBalanceFormated => _getDEuroFiatAmount(savingsBalanceFormated);
|
|
|
|
@observable
|
|
ExecutionState state = InitialExecutionState();
|
|
|
|
@observable
|
|
String interestRateFormated = '0';
|
|
|
|
@observable
|
|
BigInt accruedInterest = BigInt.zero;
|
|
|
|
@computed
|
|
String get accruedInterestFormated =>
|
|
evm!.formatterEVMAmountToDouble(amount: accruedInterest).toStringAsFixed(6);
|
|
|
|
@computed
|
|
String get fiatAccruedInterestFormated => _getDEuroFiatAmount(accruedInterestFormated);
|
|
|
|
@observable
|
|
BigInt approvedTokens = BigInt.zero;
|
|
|
|
@computed
|
|
bool get isEnabled => approvedTokens > BigInt.zero;
|
|
|
|
@computed
|
|
bool get isSavingsActionsEnabled => isEnabled && accruedInterest >= MIN_ACCRUED_INTEREST;
|
|
|
|
@observable
|
|
bool isLoading = true;
|
|
|
|
@observable
|
|
DEuroActionType actionType = DEuroActionType.none;
|
|
|
|
@observable
|
|
PendingTransaction? transaction = null;
|
|
|
|
@observable
|
|
PendingTransaction? approvalTransaction = null;
|
|
|
|
@action
|
|
Future<void> reloadSavingsUserData() async {
|
|
approvedTokens = await evm!.getDEuroSavingsApproved(_appStore.wallet!) ?? BigInt.zero;
|
|
savingsBalance = await evm!.getDEuroSavingsBalance(_appStore.wallet!) ?? BigInt.zero;
|
|
accruedInterest = await evm!.getDEuroAccruedInterest(_appStore.wallet!) ?? BigInt.zero;
|
|
isLoading = false;
|
|
}
|
|
|
|
@action
|
|
Future<void> reloadInterestRate() async {
|
|
final interestRateRaw = await evm!.getDEuroInterestRate(_appStore.wallet!) ?? BigInt.zero;
|
|
|
|
interestRateFormated = (interestRateRaw / BigInt.from(10000)).toString();
|
|
}
|
|
|
|
@action
|
|
Future<void> prepareApproval() async {
|
|
final ethBalance = balanceViewModel.balances[CryptoCurrency.eth]?.availableBalance ?? "0";
|
|
if ((double.tryParse(ethBalance) ?? 0) == 0) {
|
|
state = NoEtherState();
|
|
return;
|
|
}
|
|
try {
|
|
state = TransactionCommitting();
|
|
final priority = _appStore.settingsStore.getPriority(wallet.type, chainId: wallet.chainId)!;
|
|
final approval = await evm!.enableDEuroSaving(_appStore.wallet!, priority);
|
|
if (approval == null) {
|
|
throw Exception('DEuro saving not available');
|
|
}
|
|
approvalTransaction = approval;
|
|
state = InitialExecutionState();
|
|
} catch (e) {
|
|
state = FailureState(e.toString());
|
|
}
|
|
}
|
|
|
|
@action
|
|
Future<void> prepareSavingsEdit(String amountRaw, bool isAdding) async {
|
|
try {
|
|
state = TransactionCommitting();
|
|
|
|
if (amountRaw.isEmpty || amountRaw.trim().isEmpty) {
|
|
throw Exception('Invalid amount: amount cannot be empty');
|
|
}
|
|
|
|
final amount = tryParseFixed(amountRaw, 18);
|
|
|
|
if (amount == BigInt.zero || amount == null) {
|
|
throw Exception('Invalid amount: amount cannot be zero');
|
|
}
|
|
|
|
final priority = _appStore.settingsStore.getPriority(wallet.type, chainId: wallet.chainId)!;
|
|
actionType = isAdding ? DEuroActionType.deposit : DEuroActionType.withdraw;
|
|
final tx = await (isAdding
|
|
? evm!.addDEuroSaving(_appStore.wallet!, amount, priority)
|
|
: evm!.removeDEuroSaving(_appStore.wallet!, amount, priority));
|
|
if (tx == null) {
|
|
throw Exception('DEuro saving not available');
|
|
}
|
|
transaction = tx;
|
|
state = InitialExecutionState();
|
|
} catch (e) {
|
|
state = FailureState(e.toString());
|
|
}
|
|
}
|
|
|
|
Future<void> prepareCollectInterest() async {
|
|
if (accruedInterest < MIN_ACCRUED_INTEREST) {
|
|
state = FailureState('Accrued interest is below minimum threshold');
|
|
return;
|
|
}
|
|
|
|
final formatted = accruedInterestFormated;
|
|
if (formatted.isEmpty || formatted == '0.000000') {
|
|
state = FailureState('Invalid accrued interest amount');
|
|
return;
|
|
}
|
|
|
|
await prepareSavingsEdit(formatted, false);
|
|
}
|
|
|
|
Future<void> prepareReinvestInterest() async {
|
|
try {
|
|
state = TransactionCommitting();
|
|
actionType = DEuroActionType.reinvest;
|
|
final priority = _appStore.settingsStore.getPriority(wallet.type, chainId: wallet.chainId)!;
|
|
final tx = await evm!.reinvestDEuroInterest(_appStore.wallet!, priority);
|
|
if (tx == null) {
|
|
throw Exception('DEuro saving not available');
|
|
}
|
|
transaction = tx;
|
|
state = InitialExecutionState();
|
|
} catch (e) {
|
|
state = FailureState(e.toString());
|
|
}
|
|
}
|
|
|
|
@action
|
|
Future<void> commitTransaction() async {
|
|
if (transaction != null) {
|
|
try {
|
|
state = TransactionCommitting();
|
|
await transaction!.commit();
|
|
transaction = null;
|
|
actionType = DEuroActionType.none;
|
|
reloadSavingsUserData();
|
|
state = TransactionCommitted();
|
|
} catch (e) {
|
|
state = FailureState(e.toString());
|
|
}
|
|
}
|
|
}
|
|
|
|
@action
|
|
Future<void> commitApprovalTransaction() async {
|
|
if (approvalTransaction != null) {
|
|
try {
|
|
state = TransactionCommitting();
|
|
await approvalTransaction!.commit();
|
|
approvalTransaction = null;
|
|
reloadSavingsUserData();
|
|
state = TransactionCommitted();
|
|
} catch (e) {
|
|
state = FailureState(e.toString());
|
|
}
|
|
}
|
|
}
|
|
|
|
@action
|
|
void dismissTransaction() {
|
|
transaction = null;
|
|
approvalTransaction = null;
|
|
actionType = DEuroActionType.none;
|
|
state = InitialExecutionState();
|
|
}
|
|
|
|
String _getDEuroFiatAmount(String amount) {
|
|
try {
|
|
var dEuro = CryptoCurrency.deuro;
|
|
final keys = _fiatConversationStore.prices.keys.toList();
|
|
for (final key in keys) {
|
|
if (key.title == "DEURO") dEuro = key;
|
|
}
|
|
return calculateFiatAmount(
|
|
price: _fiatConversationStore.prices[dEuro]!,
|
|
cryptoAmount: amount,
|
|
);
|
|
} catch (_) {
|
|
return '0.00';
|
|
}
|
|
}
|
|
}
|
|
|
|
class NoEtherState extends ExecutionState {}
|
|
|
|
enum DEuroActionType {
|
|
deposit,
|
|
withdraw,
|
|
reinvest,
|
|
none;
|
|
}
|