mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-27 14:09:50 +00:00
1ce60d62b3
* Revert "Revert btc address types"
This reverts commit a49e57e3
* Re-add Bitcoin Address types
Fix conflicts with main
* fix: label issues, clear spent utxo
* chore: deps
* fix: build
* fix: missing types
* feat: new electrs API & changes, fixes for last block scanning
* Update Monero
* not sure why it's failing
* Enable Exolix
Improve service updates indicator
New versions
* Add exolix Api token to limits api
* Ignore reporting network issues
* Change default bitcoin node
* Merge main and update linux version
* Update app version [skip ci]
* New versions
* Fix conflicts and update linux version
* minor fix
* feat: Scan Silent Payments homepage toggle
* chore: build configure
* feat: generic fixes, testnet UI improvements, useSSL on bitcoin nodes
* fix: invalid Object in sendData
* feat: improve addresses page & address book displays
* feat: silent payments labeled addresses disclaimer
* fix: missing i18n
* chore: print
* feat: single block scan, rescan by date working for btc mainnet
* feat: new cake features page replace market page, move sp scan toggle, auto switch node pop up alert
* feat: delete silent addresses
* fix: red dot in non ssl nodes
* fix: inconsistent connection states, fix tx history
* fix: tx & balance displays, cpfp sending
* feat: new rust lib
* chore: node path
* fix: check node based on network
* fix: missing txcount from addresses
* style: padding in feature page cards
* fix: restore not getting all wallet addresses by type
* fix: auto switch node broken
* fix: silent payment txs not being restored
* update linux version
* feat: change scanning to subscription model, sync improvements
* fix: scan re-subscription
* fix: default nodes
* fix: improve scanning by date, fix single block scan
* refactor: common function for input tx selection
* various fixes for build issues
* initial monero.dart implementation
* ...
* multiple wallets
new lib
minor fixes
* other fixes from monero.dart and monero_c
* fix: nodes & build
* update build scripts
fix polyseed
* remove unnecessary code
* Add windows app, build scripts and build guide for it.
* Minor fix in generated monero configs
* Merge and fix main
* fix: send all with multiple outs
* add missing monero_c command
* add android build script
* update version
* Merge and fix main
* undo android ndk removal
* Fix modified exception_handler.dart
* Temporarily remove haven
* fix build issues
* fix pr script
* Fixes for build monero.dart (monero_c) for windows.
* monero build script
* wip: ios build script
* refactor: unchanged file
* Added build guides for iOS and macOS. Replaced nproc call on macOS. Added macOS configuration for configure_cake_wallet.sh script.
* Update monero.dart and monero_c versions.
* Add missed windows build scripts
* Update the application configuration for windows build script.
* Update cw_monero pubspec lock file for monero.dart
* Update pr_test_build.yml
* chore: upgrade
* chore: merge changes
* refactor: unchanged files [skip ci]
* Fix conflicts with main
* fix for multiple wallets
* update app version [skip ci]
* Add tron to windows application configuration.
* Add macOS option for description message in configure_cake_wallet.sh
* fix missing encryption utils in hardware wallet functions [skip ci]
* fix conflicts
* Include missed monero dll for windows.
* reformatting [skip ci]
* fix conflicts with main
* Disable haven configuration for iOS as default. Add ability to configure cakewallet for iOS with for configuration script. Remove cw_shared configuration for cw_monero.
* fix: scan fixes, add date, allow sending while scanning
* add missing nano secrets file [skip ci]
* ios library
* don't pull prebuilds android
* Add auto generation of manifest file for android project even for iOS, macOS, Windows.
* remove tron
* feat: sync fixes, sp settings
* feat: fix resyncing
* store crash fix
* make init async so it won't lag
disable print starts
* fix monero_c build issues
* libstdc++
* merge main and update version
* Fix MacOS saving wallet file issue
Fix Secure Storage issue (somehow)
* update pubspec.lock
* fix build script
* Use dylib as iOS framework. Use custom path for loading of iOS framework for monero.dart. Add script for generate iOS framework for monero wallet.
* fix: date from height logic, status disconnected & chain tip get
* fix: params
* feat: electrum migration if using cake electrum
* fix nodes
update versions
* re-enable tron
* update sp_scanner to work on iOS [skip ci]
* bump monero_c hash
* bump monero_c commit
* bump moneroc version
* bump monero_c commit
* Add ability to build monero wallet lib as universal lib. Update macOS build guide. Change default arch for macOS project to .
* fix: wrong socket for old electrum nodes
* update version
* Fix unchecked wallet type call
* get App Dir correctly in default_settings_migration.dart
* handle previous issue with fetching linux documents directory [skip ci]
* backup fix
* fix NTFS issues
* Add Tron
Update Linux version
* Close the wallet when the wallet gets changed
* fix: double balance
* feat: node domain
* fix: menu name
* bump monero_c commit
* fix: update tip on set scanning
* fix: connection switching back and forth
* feat: check if node is electrs, and supports sp
* chore: fix build
* minor enhancements
* fixes and enhancements
* solve conflicts with main
* Only stop wallet on rename and delete
* fix: status toggle
* minor enhancement
* Monero.com fixes
* bump monero_c commit
* update sp_scanner to include windows and linux
* merge main
* Update macOS build guide. Change brew dependencies for build unbound locally.
* fix: Tron file write, build scripts
* - merge linux with Monero Dart
- Temporarily disable Monero
* fix other issues with linux
* linux ci
fix build script
* Update pr_test_build_linux.yml
install required packages
* add linux desktop dependencies
* don't use apk in linux build releases
* don't copy the file to test-apk
* fix linux runtime issues
* remove libc++_shared.so
* fix issues with linux
* prepare both android and linux (because otherwise it will fail)
* ci script updates
* run apt update
* bump image to ubuntu 22.04
note: remember to put it down later
* bump python version
* remove some dependencies
* remove unused import
* add missing dependencies
* fix dependencies
* some fixes
* remove print [skip ci]
* Add back RunnerBase.entitlements
minor fixes [skip ci]
* fix memory leak / infinite recurrsion when opening xmr wallet
* url_launcher_linux: 3.1.1 # https://github.com/flutter/flutter/issues/153083
* fix conflicts with main
* handle walletKeysFile with encryptionUtils
* update app version [skip ci]
* add wownero [skip ci]
---------
Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
Co-authored-by: Rafael Saes <git@rafael.saes.dev>
Co-authored-by: M <m@cakewallet.com>
Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com>
408 lines
12 KiB
Dart
408 lines
12 KiB
Dart
part of 'nano.dart';
|
|
|
|
class CWNanoAccountList extends NanoAccountList {
|
|
CWNanoAccountList(this._wallet);
|
|
final Object _wallet;
|
|
|
|
@override
|
|
@computed
|
|
ObservableList<NanoAccount> get accounts {
|
|
final nanoWallet = _wallet as NanoWallet;
|
|
final accounts = nanoWallet.walletAddresses.accountList.accounts
|
|
.map((acc) => NanoAccount(id: acc.id, label: acc.label, balance: acc.balance))
|
|
.toList();
|
|
return ObservableList<NanoAccount>.of(accounts);
|
|
}
|
|
|
|
@override
|
|
void update(Object wallet) {
|
|
final nanoWallet = wallet as NanoWallet;
|
|
nanoWallet.walletAddresses.accountList.update(null);
|
|
}
|
|
|
|
@override
|
|
void refresh(Object wallet) {
|
|
final nanoWallet = wallet as NanoWallet;
|
|
nanoWallet.walletAddresses.accountList.refresh();
|
|
}
|
|
|
|
@override
|
|
Future<List<NanoAccount>> getAll(Object wallet) async {
|
|
final nanoWallet = wallet as NanoWallet;
|
|
return (await nanoWallet.walletAddresses.accountList.getAll())
|
|
.map((acc) => NanoAccount(id: acc.id, label: acc.label, balance: acc.balance))
|
|
.toList();
|
|
}
|
|
|
|
@override
|
|
Future<void> addAccount(Object wallet, {required String label}) async {
|
|
final nanoWallet = wallet as NanoWallet;
|
|
await nanoWallet.walletAddresses.accountList.addAccount(label: label);
|
|
}
|
|
|
|
@override
|
|
Future<void> setLabelAccount(Object wallet,
|
|
{required int accountIndex, required String label}) async {
|
|
final nanoWallet = wallet as NanoWallet;
|
|
await nanoWallet.walletAddresses.accountList
|
|
.setLabelAccount(accountIndex: accountIndex, label: label);
|
|
}
|
|
}
|
|
|
|
class CWNano extends Nano {
|
|
@override
|
|
NanoAccountList getAccountList(Object wallet) {
|
|
return CWNanoAccountList(wallet);
|
|
}
|
|
|
|
@override
|
|
Account getCurrentAccount(Object wallet) {
|
|
final nanoWallet = wallet as NanoWallet;
|
|
final acc = nanoWallet.walletAddresses.account;
|
|
return Account(id: acc!.id, label: acc.label, balance: acc.balance);
|
|
}
|
|
|
|
@override
|
|
void setCurrentAccount(Object wallet, int id, String label, String? balance) {
|
|
final nanoWallet = wallet as NanoWallet;
|
|
nanoWallet.walletAddresses.account = NanoAccount(id: id, label: label, balance: balance);
|
|
nanoWallet.regenerateAddress();
|
|
}
|
|
|
|
@override
|
|
List<String> getNanoWordList(String language) {
|
|
return NanoMnemomics.WORDLIST;
|
|
}
|
|
|
|
@override
|
|
WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) {
|
|
return NanoWalletService(walletInfoSource, isDirect);
|
|
}
|
|
|
|
@override
|
|
Map<String, String> getKeys(Object wallet) {
|
|
final nanoWallet = wallet as NanoWallet;
|
|
final keys = nanoWallet.keys;
|
|
return <String, String>{
|
|
"seedKey": keys.seedKey,
|
|
};
|
|
}
|
|
|
|
@override
|
|
WalletCredentials createNanoNewWalletCredentials({
|
|
required String name,
|
|
String? password,
|
|
}) =>
|
|
NanoNewWalletCredentials(
|
|
name: name,
|
|
password: password,
|
|
derivationType: DerivationType.nano,
|
|
);
|
|
|
|
@override
|
|
WalletCredentials createNanoRestoreWalletFromSeedCredentials({
|
|
required String name,
|
|
required String password,
|
|
required String mnemonic,
|
|
required DerivationType derivationType,
|
|
}) {
|
|
if (mnemonic.split(" ").length == 12 && derivationType != DerivationType.bip39) {
|
|
throw Exception("Invalid mnemonic for derivation type!");
|
|
}
|
|
|
|
return NanoRestoreWalletFromSeedCredentials(
|
|
name: name,
|
|
password: password,
|
|
mnemonic: mnemonic,
|
|
derivationType: derivationType,
|
|
);
|
|
}
|
|
|
|
@override
|
|
WalletCredentials createNanoRestoreWalletFromKeysCredentials({
|
|
required String name,
|
|
required String password,
|
|
required String seedKey,
|
|
required DerivationType derivationType,
|
|
}) {
|
|
if (seedKey.length == 128 && derivationType != DerivationType.bip39) {
|
|
throw Exception("Invalid seed key length for derivation type!");
|
|
}
|
|
|
|
return NanoRestoreWalletFromKeysCredentials(
|
|
name: name,
|
|
password: password,
|
|
seedKey: seedKey,
|
|
derivationType: derivationType,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Object createNanoTransactionCredentials(List<Output> outputs) {
|
|
return NanoTransactionCredentials(
|
|
outputs
|
|
.map((out) => OutputInfo(
|
|
fiatAmount: out.fiatAmount,
|
|
cryptoAmount: out.cryptoAmount,
|
|
address: out.address,
|
|
note: out.note,
|
|
sendAll: out.sendAll,
|
|
extractedAddress: out.extractedAddress,
|
|
isParsedAddress: out.isParsedAddress,
|
|
formattedCryptoAmount: out.formattedCryptoAmount,
|
|
))
|
|
.toList(),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<void> changeRep(Object wallet, String address) async {
|
|
if ((wallet as NanoWallet).transactionHistory.transactions.isEmpty) {
|
|
throw Exception("Can't change representative without an existing transaction history");
|
|
}
|
|
return wallet.changeRep(address);
|
|
}
|
|
|
|
@override
|
|
Future<bool> updateTransactions(Object wallet) async {
|
|
return (wallet as NanoWallet).updateTransactions();
|
|
}
|
|
|
|
@override
|
|
BigInt getTransactionAmountRaw(TransactionInfo transactionInfo) {
|
|
return (transactionInfo as NanoTransactionInfo).amountRaw;
|
|
}
|
|
|
|
@override
|
|
String getRepresentative(Object wallet) {
|
|
return (wallet as NanoWallet).representative;
|
|
}
|
|
|
|
@override
|
|
Future<List<N2Node>> getN2Reps(Object wallet) async {
|
|
return (wallet as NanoWallet).getN2Reps();
|
|
}
|
|
|
|
@override
|
|
bool isRepOk(Object wallet) {
|
|
return (wallet as NanoWallet).isRepOk;
|
|
}
|
|
}
|
|
|
|
class CWNanoUtil extends NanoUtil {
|
|
@override
|
|
bool isValidBip39Seed(String seed) {
|
|
return NanoDerivations.isValidBip39Seed(seed);
|
|
}
|
|
|
|
// number util:
|
|
|
|
static const int maxDecimalDigits = 6; // Max digits after decimal
|
|
BigInt rawPerNano = BigInt.parse("1000000000000000000000000000000");
|
|
BigInt rawPerNyano = BigInt.parse("1000000000000000000000000");
|
|
BigInt rawPerBanano = BigInt.parse("100000000000000000000000000000");
|
|
BigInt rawPerXMR = BigInt.parse("1000000000000");
|
|
BigInt convertXMRtoNano = BigInt.parse("1000000000000000000");
|
|
|
|
@override
|
|
String getRawAsUsableString(String? raw, BigInt rawPerCur) {
|
|
return NanoAmounts.getRawAsUsableString(raw, rawPerCur);
|
|
}
|
|
|
|
@override
|
|
String getRawAccuracy(String? raw, BigInt rawPerCur) {
|
|
return NanoAmounts.getRawAccuracy(raw, rawPerCur);
|
|
}
|
|
|
|
@override
|
|
String getAmountAsRaw(String amount, BigInt rawPerCur) {
|
|
return NanoAmounts.getAmountAsRaw(amount, rawPerCur);
|
|
}
|
|
|
|
@override
|
|
Future<AccountInfoResponse?> getInfoFromSeedOrMnemonic(
|
|
DerivationType derivationType, {
|
|
String? seedKey,
|
|
String? mnemonic,
|
|
required Node node,
|
|
}) async {
|
|
NanoClient nanoClient = NanoClient();
|
|
nanoClient.connect(node);
|
|
String? publicAddress;
|
|
|
|
if (seedKey == null && mnemonic == null) {
|
|
throw Exception("One of seed key OR mnemonic must be provided!");
|
|
}
|
|
|
|
try {
|
|
if (seedKey != null) {
|
|
if (seedKey.length == 64) {
|
|
try {
|
|
mnemonic = NanoDerivations.standardSeedToMnemonic(seedKey);
|
|
} catch (e) {
|
|
print("not a valid 'nano' seed key");
|
|
}
|
|
}
|
|
if (derivationType == DerivationType.bip39) {
|
|
publicAddress = await NanoDerivations.hdSeedToAddress(seedKey, index: 0);
|
|
} else if (derivationType == DerivationType.nano) {
|
|
publicAddress = await NanoDerivations.standardSeedToAddress(seedKey, index: 0);
|
|
}
|
|
}
|
|
|
|
if (derivationType == DerivationType.bip39) {
|
|
if (mnemonic != null) {
|
|
seedKey = await NanoDerivations.hdMnemonicListToSeed(mnemonic.split(' '));
|
|
publicAddress = await NanoDerivations.hdSeedToAddress(seedKey, index: 0);
|
|
}
|
|
}
|
|
|
|
if (derivationType == DerivationType.nano) {
|
|
if (mnemonic != null) {
|
|
seedKey = await NanoDerivations.standardMnemonicToSeed(mnemonic);
|
|
publicAddress = await NanoDerivations.standardSeedToAddress(seedKey, index: 0);
|
|
}
|
|
}
|
|
} catch (_) {}
|
|
|
|
if (publicAddress == null) {
|
|
// we couldn't derive a public address for the derivation type provided
|
|
// i.e. a bip39 seed was provided and we were instructed to derive a "nano" type address
|
|
return null;
|
|
}
|
|
|
|
AccountInfoResponse? accountInfo = await nanoClient.getAccountInfo(publicAddress);
|
|
if (accountInfo == null) {
|
|
accountInfo = AccountInfoResponse(
|
|
frontier: "", balance: "0", representative: "", confirmationHeight: 0);
|
|
}
|
|
accountInfo.address = publicAddress;
|
|
return accountInfo;
|
|
}
|
|
|
|
@override
|
|
Future<List<DerivationType>> compareDerivationMethods({
|
|
String? mnemonic,
|
|
String? privateKey,
|
|
required Node node,
|
|
}) async {
|
|
String? seedKey = privateKey;
|
|
|
|
if (mnemonic?.split(' ').length == 12) {
|
|
return [DerivationType.bip39];
|
|
}
|
|
if (seedKey?.length == 128) {
|
|
return [DerivationType.bip39];
|
|
} else if (seedKey?.length == 64) {
|
|
try {
|
|
mnemonic = NanoDerivations.standardSeedToMnemonic(seedKey!);
|
|
} catch (e) {
|
|
print("not a valid 'nano' seed key");
|
|
}
|
|
}
|
|
|
|
late String publicAddressStandard;
|
|
late String publicAddressBip39;
|
|
|
|
try {
|
|
NanoClient nanoClient = NanoClient();
|
|
nanoClient.connect(node);
|
|
|
|
if (mnemonic != null) {
|
|
seedKey = await NanoDerivations.hdMnemonicListToSeed(mnemonic.split(' '));
|
|
publicAddressBip39 = await NanoDerivations.hdSeedToAddress(seedKey, index: 0);
|
|
|
|
seedKey = await NanoDerivations.standardMnemonicToSeed(mnemonic);
|
|
publicAddressStandard = await NanoDerivations.standardSeedToAddress(seedKey, index: 0);
|
|
} else if (seedKey != null) {
|
|
try {
|
|
publicAddressBip39 = await NanoDerivations.hdSeedToAddress(seedKey, index: 0);
|
|
} catch (e) {
|
|
return [DerivationType.nano];
|
|
}
|
|
try {
|
|
publicAddressStandard = await NanoDerivations.standardSeedToAddress(seedKey, index: 0);
|
|
} catch (e) {
|
|
return [DerivationType.bip39];
|
|
}
|
|
}
|
|
|
|
// check if account has a history:
|
|
AccountInfoResponse? bip39Info;
|
|
AccountInfoResponse? standardInfo;
|
|
|
|
try {
|
|
bip39Info = await nanoClient.getAccountInfo(publicAddressBip39);
|
|
} catch (e) {
|
|
bip39Info = null;
|
|
}
|
|
try {
|
|
standardInfo = await nanoClient.getAccountInfo(publicAddressStandard);
|
|
} catch (e) {
|
|
standardInfo = null;
|
|
}
|
|
|
|
// one of these is *probably* null:
|
|
if (bip39Info == null && standardInfo != null) {
|
|
return [DerivationType.nano];
|
|
} else if (standardInfo == null && bip39Info != null) {
|
|
return [DerivationType.bip39];
|
|
}
|
|
|
|
// we don't know for sure:
|
|
return [DerivationType.nano, DerivationType.bip39];
|
|
} catch (e) {
|
|
return [DerivationType.nano, DerivationType.bip39];
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<List<DerivationInfo>> getDerivationsFromMnemonic({
|
|
String? mnemonic,
|
|
String? seedKey,
|
|
required Node node,
|
|
}) async {
|
|
List<DerivationInfo> list = [];
|
|
|
|
List<DerivationType> possibleDerivationTypes = await compareDerivationMethods(
|
|
mnemonic: mnemonic,
|
|
privateKey: seedKey,
|
|
node: node,
|
|
);
|
|
if (possibleDerivationTypes.length == 1) {
|
|
return [DerivationInfo(derivationType: possibleDerivationTypes.first)];
|
|
}
|
|
|
|
AccountInfoResponse? bip39Info = await nanoUtil!.getInfoFromSeedOrMnemonic(
|
|
DerivationType.bip39,
|
|
mnemonic: mnemonic,
|
|
seedKey: seedKey,
|
|
node: node,
|
|
);
|
|
AccountInfoResponse? standardInfo = await nanoUtil!.getInfoFromSeedOrMnemonic(
|
|
DerivationType.nano,
|
|
mnemonic: mnemonic,
|
|
seedKey: seedKey,
|
|
node: node,
|
|
);
|
|
|
|
if (standardInfo?.confirmationHeight != null && standardInfo!.confirmationHeight > 0) {
|
|
list.add(DerivationInfo(
|
|
derivationType: DerivationType.nano,
|
|
balance: nanoUtil!.getRawAsUsableString(standardInfo.balance, nanoUtil!.rawPerNano),
|
|
address: standardInfo.address!,
|
|
transactionsCount: standardInfo.confirmationHeight,
|
|
));
|
|
}
|
|
|
|
if (bip39Info?.confirmationHeight != null && bip39Info!.confirmationHeight > 0) {
|
|
list.add(DerivationInfo(
|
|
derivationType: DerivationType.bip39,
|
|
balance: nanoUtil!.getRawAsUsableString(bip39Info.balance, nanoUtil!.rawPerNano),
|
|
address: bip39Info.address!,
|
|
transactionsCount: bip39Info.confirmationHeight,
|
|
));
|
|
}
|
|
return list;
|
|
}
|
|
}
|