feat: add flatpak build variable to use different default storage location to avoid needing filesystem=home permission

This commit is contained in:
Rafael Saes 2024-01-30 14:20:10 -03:00
parent 67a96807d1
commit 54be0f863c
44 changed files with 1014 additions and 702 deletions

7
.gitignore vendored
View file

@ -158,3 +158,10 @@ macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
macos/Runner/Configs/AppInfo.xcconfig
# Linux flatpak build related
.flatpak-builder/
export/
cake_wallet.flatpak
lib/core/flatpak.dart

View file

@ -27,16 +27,16 @@ CakeWallet requires some packages to be install on your build system. You may ea
> To check what gcc version you are using:
>
> ```bash
> $ gcc --version
> $ g++ --version
> gcc --version
> g++ --version
> ```
>
> If you are using gcc version newer than 10, then you need to downgrade to version 10.4.0:
>
> ```bash
> $ sudo apt install gcc-10 g++-10
> $ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10
> $ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10
> sudo apt install gcc-10 g++-10
> sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10
> sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10
> ```
> [!NOTE]
@ -44,7 +44,7 @@ CakeWallet requires some packages to be install on your build system. You may ea
> Alternatively, you can use the [nix-shell](https://nixos.org/) with the `gcc10.nix` file\
> present on `scripts/linux` like so:
> ```bash
> $ nix-shell gcc10.nix
> nix-shell gcc10.nix
> ```
> This will get you in a nix environment with all the required dependencies that you can use to build the software from,\
> and it works in any linux distro.
@ -145,31 +145,38 @@ Path to executable file will be:
# Flatpak
For package the built application into flatpak you need fistly to install `flatpak` and `flatpak-builder`:
> [!NOTE]
>
> To package the built application into flatpak, you will need to follow the steps above
> but replace the `$ source ./app_env.sh cakewallet` step with `$ source ./app_env.sh cakewallet-flatpak` first.
Install `flatpak` and `flatpak-builder`:
`$ sudo apt install flatpak flatpak-builder`
Then need to [add flathub](https://flatpak.org/setup/Ubuntu) (or just `$ flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo`). Then need to install freedesktop runtime and sdk:
Then need to [add flathub](https://flatpak.org/setup/Ubuntu) (or just `$ flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo`).
Install the freedesktop runtime and sdk:
`$ flatpak install flathub org.freedesktop.Platform//22.08 org.freedesktop.Sdk//22.08`
`$ flatpak install flathub org.freedesktop.Platform//23.08 org.freedesktop.Sdk//23.08`
To build with using of `flatpak-build` directory run next:
Next, to build using `flatpak-build` run:
`$ flatpak-builder --force-clean flatpak-build com.cakewallet.CakeWallet.yml`
And then export bundle:
And then export the bundle:
`$ flatpak build-export export flatpak-build`
```bash
flatpak build-export export flatpak-build
flatpak build-bundle export cake_wallet.flatpak com.cakewallet.CakeWallet
```
`$ flatpak build-bundle export cake_wallet.flatpak com.cakewallet.CakeWallet`
Result file: `cake_wallet.flatpak` should be generated in the current directory.
Result file: `cake_wallet.flatpak` should be generated in current directory.
For install generated flatpak file use:
To install the generated flatpak file use:
`$ flatpak --user install cake_wallet.flatpak`
For run the installed application run:
To run the installed application run:
`$ flatpak run com.cakewallet.CakeWallet`

View file

@ -1,6 +1,6 @@
app-id: com.cakewallet.CakeWallet
runtime: org.freedesktop.Platform
runtime-version: '22.08'
runtime-version: '23.08'
sdk: org.freedesktop.Sdk
command: cake_wallet
separate-locales: false
@ -11,7 +11,6 @@ finish-args:
- --device=dri
- --socket=pulseaudio
- --share=network
- --filesystem=home
modules:
- name: cake_wallet
buildsystem: simple

View file

@ -18,37 +18,37 @@ part 'bitcoin_wallet.g.dart';
class BitcoinWallet = BitcoinWalletBase with _$BitcoinWallet;
abstract class BitcoinWalletBase extends ElectrumWallet with Store {
BitcoinWalletBase(
{required String mnemonic,
required String password,
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required Uint8List seedBytes,
required EncryptionFileUtils encryptionFileUtils,
List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0})
: super(
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
networkType: bitcoin.bitcoin,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
seedBytes: seedBytes,
currency: CryptoCurrency.btc,
encryptionFileUtils: encryptionFileUtils) {
walletAddresses = BitcoinWalletAddresses(
walletInfo,
BitcoinWalletBase({
required String mnemonic,
required String password,
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required Uint8List seedBytes,
required EncryptionFileUtils encryptionFileUtils,
List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0,
required super.isFlatpak,
}) : super(
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
networkType: bitcoin.bitcoin,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
seedBytes: seedBytes,
currency: CryptoCurrency.btc,
encryptionFileUtils: encryptionFileUtils,
) {
walletAddresses = BitcoinWalletAddresses(walletInfo,
electrumClient: electrumClient,
initialAddresses: initialAddresses,
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex,
mainHd: hd,
sideHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType)
.derivePath("m/0'/1"),
sideHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/1"),
networkType: networkType);
autorun((_) {
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
@ -64,19 +64,22 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0
int initialChangeAddressIndex = 0,
required bool isFlatpak,
}) async {
return BitcoinWallet(
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
encryptionFileUtils: encryptionFileUtils,
seedBytes: await mnemonicToSeedBytes(mnemonic),
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex);
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
encryptionFileUtils: encryptionFileUtils,
seedBytes: await mnemonicToSeedBytes(mnemonic),
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex,
isFlatpak: isFlatpak,
);
}
static Future<BitcoinWallet> open({
@ -85,18 +88,23 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required String password,
required EncryptionFileUtils encryptionFileUtils,
required bool isFlatpak,
}) async {
final snp = await ElectrumWallletSnapshot.load(encryptionFileUtils, name, walletInfo.type, password);
final snp = await ElectrumWallletSnapshot.load(
encryptionFileUtils, name, walletInfo.type, password, isFlatpak);
return BitcoinWallet(
mnemonic: snp.mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp.addresses,
initialBalance: snp.balance,
seedBytes: await mnemonicToSeedBytes(snp.mnemonic),
encryptionFileUtils: encryptionFileUtils,
initialRegularAddressIndex: snp.regularAddressIndex,
initialChangeAddressIndex: snp.changeAddressIndex);
mnemonic: snp.mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp.addresses,
initialBalance: snp.balance,
seedBytes: await mnemonicToSeedBytes(snp.mnemonic),
encryptionFileUtils: encryptionFileUtils,
initialRegularAddressIndex: snp.regularAddressIndex,
initialChangeAddressIndex: snp.changeAddressIndex,
isFlatpak: isFlatpak,
);
}
}
}

View file

@ -13,15 +13,15 @@ import 'package:cw_core/wallet_type.dart';
import 'package:hive/hive.dart';
import 'package:collection/collection.dart';
class BitcoinWalletService extends WalletService<
BitcoinNewWalletCredentials,
BitcoinRestoreWalletFromSeedCredentials,
BitcoinRestoreWalletFromWIFCredentials> {
BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect);
class BitcoinWalletService extends WalletService<BitcoinNewWalletCredentials,
BitcoinRestoreWalletFromSeedCredentials, BitcoinRestoreWalletFromWIFCredentials> {
BitcoinWalletService(
this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect, this.isFlatpak);
final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
final bool isDirect;
final bool isFlatpak;
@override
WalletType getType() => WalletType.bitcoin;
@ -29,11 +29,13 @@ class BitcoinWalletService extends WalletService<
@override
Future<BitcoinWallet> create(BitcoinNewWalletCredentials credentials) async {
final wallet = await BitcoinWalletBase.create(
mnemonic: await generateMnemonic(),
password: credentials.password!,
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
mnemonic: await generateMnemonic(),
password: credentials.password!,
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.save();
await wallet.init();
return wallet;
@ -41,41 +43,45 @@ class BitcoinWalletService extends WalletService<
@override
Future<bool> isWalletExit(String name) async =>
File(await pathForWallet(name: name, type: getType())).existsSync();
File(await pathForWallet(name: name, type: getType(), isFlatpak: isFlatpak)).existsSync();
@override
Future<BitcoinWallet> openWallet(String name, String password) async {
final walletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(name, getType()))!;
final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
final wallet = await BitcoinWalletBase.open(
password: password,
name: name,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
password: password,
name: name,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.init();
return wallet;
}
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType()))
File(await pathForWalletDir(name: wallet, type: getType(), isFlatpak: isFlatpak))
.delete(recursive: true);
final walletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(wallet, getType()))!;
final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
await walletInfoSource.delete(walletInfo.key);
}
@override
Future<void> rename(String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(currentName, getType()))!;
final currentWalletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
final currentWallet = await BitcoinWalletBase.open(
password: password,
name: currentName,
walletInfo: currentWalletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
password: password,
name: currentName,
walletInfo: currentWalletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await currentWallet.renameWalletFiles(newName);
@ -87,25 +93,25 @@ class BitcoinWalletService extends WalletService<
}
@override
Future<BitcoinWallet> restoreFromKeys(
BitcoinRestoreWalletFromWIFCredentials credentials) async =>
Future<BitcoinWallet> restoreFromKeys(BitcoinRestoreWalletFromWIFCredentials credentials) async =>
throw UnimplementedError();
@override
Future<BitcoinWallet> restoreFromSeed(
BitcoinRestoreWalletFromSeedCredentials credentials) async {
Future<BitcoinWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials) async {
if (!validateMnemonic(credentials.mnemonic)) {
throw BitcoinMnemonicIsIncorrectException();
}
final wallet = await BitcoinWalletBase.create(
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.save();
await wallet.init();
return wallet;
}
}
}

View file

@ -4,23 +4,22 @@ import 'package:cw_core/encryption_file_utils.dart';
import 'package:cw_bitcoin/electrum_transaction_info.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/utils/file.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_bitcoin/electrum_transaction_info.dart';
part 'electrum_transaction_history.g.dart';
const transactionsHistoryFileName = 'transactions.json';
class ElectrumTransactionHistory = ElectrumTransactionHistoryBase
with _$ElectrumTransactionHistory;
class ElectrumTransactionHistory = ElectrumTransactionHistoryBase with _$ElectrumTransactionHistory;
abstract class ElectrumTransactionHistoryBase
extends TransactionHistoryBase<ElectrumTransactionInfo> with Store {
ElectrumTransactionHistoryBase(
{required this.walletInfo, required String password, required this.encryptionFileUtils})
{required this.walletInfo,
required String password,
required this.encryptionFileUtils,
required this.isFlatpak})
: _password = password,
_height = 0 {
transactions = ObservableMap<String, ElectrumTransactionInfo>();
@ -28,14 +27,14 @@ abstract class ElectrumTransactionHistoryBase
final WalletInfo walletInfo;
final EncryptionFileUtils encryptionFileUtils;
final bool isFlatpak;
String _password;
int _height;
Future<void> init() async => await _load();
@override
void addOne(ElectrumTransactionInfo transaction) =>
transactions[transaction.id] = transaction;
void addOne(ElectrumTransactionInfo transaction) => transactions[transaction.id] = transaction;
@override
void addMany(Map<String, ElectrumTransactionInfo> transactions) =>
@ -44,11 +43,10 @@ abstract class ElectrumTransactionHistoryBase
@override
Future<void> save() async {
try {
final dirPath =
await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
final dirPath = await pathForWalletDir(
name: walletInfo.name, type: walletInfo.type, isFlatpak: isFlatpak);
final path = '$dirPath/$transactionsHistoryFileName';
final data =
json.encode({'height': _height, 'transactions': transactions});
final data = json.encode({'height': _height, 'transactions': transactions});
await encryptionFileUtils.write(path: path, password: _password, data: data);
} catch (e) {
print('Error while save bitcoin transaction history: ${e.toString()}');
@ -62,7 +60,7 @@ abstract class ElectrumTransactionHistoryBase
Future<Map<String, dynamic>> _read() async {
final dirPath =
await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
await pathForWalletDir(name: walletInfo.name, type: walletInfo.type, isFlatpak: isFlatpak);
final path = '$dirPath/$transactionsHistoryFileName';
final content = await encryptionFileUtils.read(path: path, password: _password);
return json.decode(content) as Map<String, dynamic>;
@ -88,7 +86,5 @@ abstract class ElectrumTransactionHistoryBase
}
}
void _update(ElectrumTransactionInfo transaction) =>
transactions[transaction.id] = transaction;
void _update(ElectrumTransactionInfo transaction) => transactions[transaction.id] = transaction;
}

View file

@ -48,16 +48,17 @@ abstract class ElectrumWalletBase
with Store {
ElectrumWalletBase(
{required String password,
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required this.networkType,
required this.mnemonic,
required Uint8List seedBytes,
required this.encryptionFileUtils,
List<BitcoinAddressRecord>? initialAddresses,
ElectrumClient? electrumClient,
ElectrumBalance? initialBalance,
CryptoCurrency? currency})
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required this.networkType,
required this.mnemonic,
required Uint8List seedBytes,
required this.encryptionFileUtils,
required this.isFlatpak,
List<BitcoinAddressRecord>? initialAddresses,
ElectrumClient? electrumClient,
ElectrumBalance? initialBalance,
CryptoCurrency? currency})
: hd = currency == CryptoCurrency.bch
? bitcoinCashHDWallet(seedBytes)
: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/0"),
@ -78,13 +79,15 @@ abstract class ElectrumWalletBase
super(walletInfo) {
this.electrumClient = electrumClient ?? ElectrumClient();
this.walletInfo = walletInfo;
transactionHistory =
ElectrumTransactionHistory(
walletInfo: walletInfo,
password: password,
encryptionFileUtils: encryptionFileUtils);
transactionHistory = ElectrumTransactionHistory(
walletInfo: walletInfo,
password: password,
encryptionFileUtils: encryptionFileUtils,
isFlatpak: isFlatpak);
}
final bool isFlatpak;
static bitcoin.HDWallet bitcoinCashHDWallet(Uint8List seedBytes) =>
bitcoin.HDWallet.fromSeed(seedBytes).derivePath("m/44'/145'/0'/0");
@ -440,19 +443,23 @@ abstract class ElectrumWalletBase
@override
Future<void> renameWalletFiles(String newWalletName) async {
final currentWalletPath = await pathForWallet(name: walletInfo.name, type: type);
final currentWalletPath =
await pathForWallet(name: walletInfo.name, type: type, isFlatpak: isFlatpak);
final currentWalletFile = File(currentWalletPath);
final currentDirPath = await pathForWalletDir(name: walletInfo.name, type: type);
final currentDirPath =
await pathForWalletDir(name: walletInfo.name, type: type, isFlatpak: isFlatpak);
final currentTransactionsFile = File('$currentDirPath/$transactionsHistoryFileName');
// Copies current wallet files into new wallet name's dir and files
if (currentWalletFile.existsSync()) {
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
final newWalletPath =
await pathForWallet(name: newWalletName, type: type, isFlatpak: isFlatpak);
await currentWalletFile.copy(newWalletPath);
}
if (currentTransactionsFile.existsSync()) {
final newDirPath = await pathForWalletDir(name: newWalletName, type: type);
final newDirPath =
await pathForWalletDir(name: newWalletName, type: type, isFlatpak: isFlatpak);
await currentTransactionsFile.copy('$newDirPath/$transactionsHistoryFileName');
}
@ -480,7 +487,8 @@ abstract class ElectrumWalletBase
} catch (_) {}
}
Future<String> makePath() async => pathForWallet(name: walletInfo.name, type: walletInfo.type);
Future<String> makePath() async =>
pathForWallet(name: walletInfo.name, type: walletInfo.type, isFlatpak: isFlatpak);
Future<void> updateUnspent() async {
final unspent = await Future.wait(walletAddresses.addresses.map((address) => electrumClient

View file

@ -3,7 +3,6 @@ import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/electrum_balance.dart';
import 'package:cw_core/encryption_file_utils.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/utils/file.dart';
import 'package:cw_core/wallet_type.dart';
class ElectrumWallletSnapshot {
@ -15,7 +14,8 @@ class ElectrumWallletSnapshot {
required this.addresses,
required this.balance,
required this.regularAddressIndex,
required this.changeAddressIndex});
required this.changeAddressIndex,
});
final String name;
final String password;
@ -27,8 +27,9 @@ class ElectrumWallletSnapshot {
int regularAddressIndex;
int changeAddressIndex;
static Future<ElectrumWallletSnapshot> load(EncryptionFileUtils encryptionFileUtils, String name, WalletType type, String password) async {
final path = await pathForWallet(name: name, type: type);
static Future<ElectrumWallletSnapshot> load(EncryptionFileUtils encryptionFileUtils, String name,
WalletType type, String password, bool isFlatpak) async {
final path = await pathForWallet(name: name, type: type, isFlatpak: isFlatpak);
final jsonSource = await encryptionFileUtils.read(path: path, password: password);
final data = json.decode(jsonSource) as Map;
final addressesTmp = data['addresses'] as List? ?? <Object>[];
@ -55,6 +56,7 @@ class ElectrumWallletSnapshot {
addresses: addresses,
balance: balance,
regularAddressIndex: regularAddressIndex,
changeAddressIndex: changeAddressIndex);
changeAddressIndex: changeAddressIndex,
);
}
}

View file

@ -21,18 +21,19 @@ part 'litecoin_wallet.g.dart';
class LitecoinWallet = LitecoinWalletBase with _$LitecoinWallet;
abstract class LitecoinWalletBase extends ElectrumWallet with Store {
LitecoinWalletBase(
{required String mnemonic,
required String password,
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required Uint8List seedBytes,
required EncryptionFileUtils encryptionFileUtils,
List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0})
: super(
LitecoinWalletBase({
required String mnemonic,
required String password,
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required Uint8List seedBytes,
required EncryptionFileUtils encryptionFileUtils,
List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0,
required super.isFlatpak,
}) : super(
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
@ -44,16 +45,15 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
encryptionFileUtils: encryptionFileUtils,
currency: CryptoCurrency.ltc) {
walletAddresses = LitecoinWalletAddresses(
walletInfo,
electrumClient: electrumClient,
initialAddresses: initialAddresses,
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex,
mainHd: hd,
sideHd: bitcoin.HDWallet
.fromSeed(seedBytes, network: networkType)
.derivePath("m/0'/1"),
networkType: networkType,);
walletInfo,
electrumClient: electrumClient,
initialAddresses: initialAddresses,
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex,
mainHd: hd,
sideHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/1"),
networkType: networkType,
);
autorun((_) {
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
});
@ -68,19 +68,22 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0
int initialChangeAddressIndex = 0,
required bool isFlatpak,
}) async {
return LitecoinWallet(
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
seedBytes: await mnemonicToSeedBytes(mnemonic),
encryptionFileUtils: encryptionFileUtils,
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex);
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
seedBytes: await mnemonicToSeedBytes(mnemonic),
encryptionFileUtils: encryptionFileUtils,
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex,
isFlatpak: isFlatpak,
);
}
static Future<LitecoinWallet> open({
@ -88,20 +91,24 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required String password,
required EncryptionFileUtils encryptionFileUtils
required EncryptionFileUtils encryptionFileUtils,
required bool isFlatpak,
}) async {
final snp = await ElectrumWallletSnapshot.load(encryptionFileUtils, name, walletInfo.type, password);
final snp = await ElectrumWallletSnapshot.load(
encryptionFileUtils, name, walletInfo.type, password, isFlatpak);
return LitecoinWallet(
mnemonic: snp.mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp.addresses,
initialBalance: snp.balance,
seedBytes: await mnemonicToSeedBytes(snp.mnemonic),
encryptionFileUtils: encryptionFileUtils,
initialRegularAddressIndex: snp.regularAddressIndex,
initialChangeAddressIndex: snp.changeAddressIndex);
mnemonic: snp.mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp.addresses,
initialBalance: snp.balance,
seedBytes: await mnemonicToSeedBytes(snp.mnemonic),
encryptionFileUtils: encryptionFileUtils,
initialRegularAddressIndex: snp.regularAddressIndex,
initialChangeAddressIndex: snp.changeAddressIndex,
isFlatpak: isFlatpak,
);
}
@override

View file

@ -13,15 +13,15 @@ import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:collection/collection.dart';
class LitecoinWalletService extends WalletService<
BitcoinNewWalletCredentials,
BitcoinRestoreWalletFromSeedCredentials,
BitcoinRestoreWalletFromWIFCredentials> {
LitecoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect);
class LitecoinWalletService extends WalletService<BitcoinNewWalletCredentials,
BitcoinRestoreWalletFromSeedCredentials, BitcoinRestoreWalletFromWIFCredentials> {
LitecoinWalletService(
this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect, this.isFlatpak);
final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
final bool isDirect;
final bool isFlatpak;
@override
WalletType getType() => WalletType.litecoin;
@ -29,11 +29,13 @@ class LitecoinWalletService extends WalletService<
@override
Future<LitecoinWallet> create(BitcoinNewWalletCredentials credentials) async {
final wallet = await LitecoinWalletBase.create(
mnemonic: await generateMnemonic(),
password: credentials.password!,
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
mnemonic: await generateMnemonic(),
password: credentials.password!,
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.save();
await wallet.init();
@ -42,41 +44,45 @@ class LitecoinWalletService extends WalletService<
@override
Future<bool> isWalletExit(String name) async =>
File(await pathForWallet(name: name, type: getType())).existsSync();
File(await pathForWallet(name: name, type: getType(), isFlatpak: isFlatpak)).existsSync();
@override
Future<LitecoinWallet> openWallet(String name, String password) async {
final walletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(name, getType()))!;
final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
final wallet = await LitecoinWalletBase.open(
password: password,
name: name,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
password: password,
name: name,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.init();
return wallet;
}
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType()))
File(await pathForWalletDir(name: wallet, type: getType(), isFlatpak: isFlatpak))
.delete(recursive: true);
final walletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(wallet, getType()))!;
final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
await walletInfoSource.delete(walletInfo.key);
}
@override
Future<void> rename(String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(currentName, getType()))!;
final currentWalletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
final currentWallet = await LitecoinWalletBase.open(
password: password,
name: currentName,
walletInfo: currentWalletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
password: password,
name: currentName,
walletInfo: currentWalletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await currentWallet.renameWalletFiles(newName);
@ -100,11 +106,13 @@ class LitecoinWalletService extends WalletService<
}
final wallet = await LitecoinWalletBase.create(
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.save();
await wallet.init();
return wallet;

View file

@ -29,18 +29,19 @@ part 'bitcoin_cash_wallet.g.dart';
class BitcoinCashWallet = BitcoinCashWalletBase with _$BitcoinCashWallet;
abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
BitcoinCashWalletBase(
{required String mnemonic,
required String password,
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required Uint8List seedBytes,
required EncryptionFileUtils encryptionFileUtils,
List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0})
: super(
BitcoinCashWalletBase({
required String mnemonic,
required String password,
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required Uint8List seedBytes,
required EncryptionFileUtils encryptionFileUtils,
List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0,
required super.isFlatpak,
}) : super(
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
@ -57,36 +58,38 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex,
mainHd: hd,
sideHd: bitcoin.HDWallet.fromSeed(seedBytes)
.derivePath("m/44'/145'/0'/1"),
sideHd: bitcoin.HDWallet.fromSeed(seedBytes).derivePath("m/44'/145'/0'/1"),
networkType: networkType);
autorun((_) {
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
});
}
static Future<BitcoinCashWallet> create(
{required String mnemonic,
required String password,
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required EncryptionFileUtils encryptionFileUtils,
List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0}) async {
static Future<BitcoinCashWallet> create({
required String mnemonic,
required String password,
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required EncryptionFileUtils encryptionFileUtils,
List<BitcoinAddressRecord>? initialAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0,
required bool isFlatpak,
}) async {
return BitcoinCashWallet(
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
seedBytes: await Mnemonic.toSeed(mnemonic),
encryptionFileUtils: encryptionFileUtils,
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex);
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
seedBytes: await Mnemonic.toSeed(mnemonic),
encryptionFileUtils: encryptionFileUtils,
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex,
isFlatpak: isFlatpak,
);
}
static Future<BitcoinCashWallet> open({
@ -95,19 +98,23 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required String password,
required EncryptionFileUtils encryptionFileUtils,
required bool isFlatpak,
}) async {
final snp = await ElectrumWallletSnapshot.load(encryptionFileUtils, name, walletInfo.type, password);
final snp = await ElectrumWallletSnapshot.load(
encryptionFileUtils, name, walletInfo.type, password, isFlatpak);
return BitcoinCashWallet(
mnemonic: snp.mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp.addresses,
initialBalance: snp.balance,
seedBytes: await Mnemonic.toSeed(snp.mnemonic),
encryptionFileUtils: encryptionFileUtils,
initialRegularAddressIndex: snp.regularAddressIndex,
initialChangeAddressIndex: snp.changeAddressIndex);
mnemonic: snp.mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp.addresses,
initialBalance: snp.balance,
seedBytes: await Mnemonic.toSeed(snp.mnemonic),
encryptionFileUtils: encryptionFileUtils,
initialRegularAddressIndex: snp.regularAddressIndex,
initialChangeAddressIndex: snp.changeAddressIndex,
isFlatpak: isFlatpak,
);
}
@override
@ -277,9 +284,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
electrumClient: electrumClient, amount: amount, fee: fee);
}
bitbox.ECPair generateKeyPair(
{required bitcoin.HDWallet hd,
required int index}) =>
bitbox.ECPair generateKeyPair({required bitcoin.HDWallet hd, required int index}) =>
bitbox.ECPair.fromWIF(hd.derive(index).wif!);
@override
@ -332,7 +337,8 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
final index = address != null
? walletAddresses.addresses
.firstWhere((element) => element.address == AddressUtils.toLegacyAddress(address))
.index : null;
.index
: null;
final HD = index == null ? hd : hd.derive(index);
return base64Encode(HD.signMessage(message));
}

View file

@ -13,35 +13,37 @@ import 'package:collection/collection.dart';
import 'package:hive/hive.dart';
class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredentials,
BitcoinCashRestoreWalletFromSeedCredentials,
BitcoinCashRestoreWalletFromWIFCredentials> {
BitcoinCashWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect);
BitcoinCashRestoreWalletFromSeedCredentials, BitcoinCashRestoreWalletFromWIFCredentials> {
BitcoinCashWalletService(
this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect, this.isFlatpak);
final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
final bool isDirect;
final bool isFlatpak;
@override
WalletType getType() => WalletType.bitcoinCash;
@override
Future<bool> isWalletExit(String name) async =>
File(await pathForWallet(name: name, type: getType())).existsSync();
File(await pathForWallet(name: name, type: getType(), isFlatpak: isFlatpak)).existsSync();
@override
Future<BitcoinCashWallet> create(
credentials) async {
Future<BitcoinCashWallet> create(credentials) async {
final strength = (credentials.seedPhraseLength == 12)
? 128
: (credentials.seedPhraseLength == 24)
? 256
: 128;
? 256
: 128;
final wallet = await BitcoinCashWalletBase.create(
mnemonic: await Mnemonic.generate(strength: strength),
password: credentials.password!,
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
mnemonic: await Mnemonic.generate(strength: strength),
password: credentials.password!,
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.save();
await wallet.init();
return wallet;
@ -49,35 +51,41 @@ class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredent
@override
Future<BitcoinCashWallet> openWallet(String name, String password) async {
final walletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(name, getType()))!;
final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
final wallet = await BitcoinCashWalletBase.open(
password: password, name: name, walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
password: password,
name: name,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.init();
return wallet;
}
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType()))
File(await pathForWalletDir(name: wallet, type: getType(), isFlatpak: isFlatpak))
.delete(recursive: true);
final walletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(wallet, getType()))!;
final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
await walletInfoSource.delete(walletInfo.key);
}
@override
Future<void> rename(String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(currentName, getType()))!;
final currentWalletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
final currentWallet = await BitcoinCashWalletBase.open(
password: password,
name: currentName,
walletInfo: currentWalletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
password: password,
name: currentName,
walletInfo: currentWalletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await currentWallet.renameWalletFiles(newName);
@ -89,8 +97,7 @@ class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredent
}
@override
Future<BitcoinCashWallet>
restoreFromKeys(credentials) {
Future<BitcoinCashWallet> restoreFromKeys(credentials) {
// TODO: implement restoreFromKeys
throw UnimplementedError('restoreFromKeys() is not implemented');
}
@ -103,11 +110,13 @@ class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredent
}
final wallet = await BitcoinCashWalletBase.create(
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.save();
await wallet.init();
return wallet;

View file

@ -10,8 +10,8 @@ String backupFileName(String originalPath) {
return pathParts.join('/');
}
Future<void> backupWalletFiles(String name) async {
final path = await pathForWallet(name: name, type: WalletType.monero);
Future<void> backupWalletFiles(String name, bool isFlatpak) async {
final path = await pathForWallet(name: name, type: WalletType.monero, isFlatpak: isFlatpak);
final cacheFile = File(path);
final keysFile = File('$path.keys');
final addressListFile = File('$path.address.txt');
@ -32,8 +32,9 @@ Future<void> backupWalletFiles(String name) async {
}
}
Future<void> restoreWalletFiles(String name) async {
final walletDirPath = await pathForWalletDir(name: name, type: WalletType.monero);
Future<void> restoreWalletFiles(String name, bool isFlatpak) async {
final walletDirPath =
await pathForWalletDir(name: name, type: WalletType.monero, isFlatpak: isFlatpak);
final cacheFilePath = '$walletDirPath/$name';
final keysFilePath = '$walletDirPath/$name.keys';
final addressListFilePath = '$walletDirPath/$name.address.txt';
@ -54,8 +55,9 @@ Future<void> restoreWalletFiles(String name) async {
}
}
Future<bool> backupWalletFilesExists(String name) async {
final walletDirPath = await pathForWalletDir(name: name, type: WalletType.monero);
Future<bool> backupWalletFilesExists(String name, bool isFlatpak) async {
final walletDirPath =
await pathForWalletDir(name: name, type: WalletType.monero, isFlatpak: isFlatpak);
final cacheFilePath = '$walletDirPath/$name';
final keysFilePath = '$walletDirPath/$name.keys';
final addressListFilePath = '$walletDirPath/$name.address.txt';
@ -63,13 +65,13 @@ Future<bool> backupWalletFilesExists(String name) async {
final backupKeysFile = File(backupFileName(keysFilePath));
final backupAddressListFile = File(backupFileName(addressListFilePath));
return backupCacheFile.existsSync()
&& backupKeysFile.existsSync()
&& backupAddressListFile.existsSync();
return backupCacheFile.existsSync() &&
backupKeysFile.existsSync() &&
backupAddressListFile.existsSync();
}
Future<void> removeCache(String name) async {
final path = await pathForWallet(name: name, type: WalletType.monero);
Future<void> removeCache(String name, bool isFlatpak) async {
final path = await pathForWallet(name: name, type: WalletType.monero, isFlatpak: isFlatpak);
final cacheFile = File(path);
if (cacheFile.existsSync()) {
@ -77,12 +79,12 @@ Future<void> removeCache(String name) async {
}
}
Future<void> restoreOrResetWalletFiles(String name) async {
final backupsExists = await backupWalletFilesExists(name);
Future<void> restoreOrResetWalletFiles(String name, bool isFlatpak) async {
final backupsExists = await backupWalletFilesExists(name, isFlatpak);
if (backupsExists) {
await restoreWalletFiles(name);
await restoreWalletFiles(name, isFlatpak);
}
removeCache(name);
}
removeCache(name, isFlatpak);
}

View file

@ -1,11 +1,10 @@
import 'dart:io';
import 'package:cw_core/root_dir.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart';
import 'package:path_provider/path_provider.dart';
Future<String> pathForWalletDir({required String name, required WalletType type}) async {
final root = await getAppDir();
Future<String> pathForWalletDir(
{required String name, required WalletType type, required bool isFlatpak}) async {
final root = await getAppDir(isFlatpak: isFlatpak);
final prefix = walletTypeToString(type).toLowerCase();
final walletsDir = Directory('${root.path}/wallets');
final walletDire = Directory('${walletsDir.path}/$prefix/$name');
@ -17,13 +16,14 @@ Future<String> pathForWalletDir({required String name, required WalletType type
return walletDire.path;
}
Future<String> pathForWallet({required String name, required WalletType type}) async =>
await pathForWalletDir(name: name, type: type)
Future<String> pathForWallet(
{required String name, required WalletType type, required bool isFlatpak}) async =>
await pathForWalletDir(name: name, type: type, isFlatpak: isFlatpak)
.then((path) => path + '/$name');
Future<String> outdatedAndroidPathForWalletDir({required String name}) async {
final directory = await getAppDir();
Future<String> outdatedAndroidPathForWalletDir({required String name, required bool isFlatpak}) async {
final directory = await getAppDir(isFlatpak: isFlatpak);
final pathDir = directory.path + '/$name';
return pathDir;
}
}

View file

@ -5,7 +5,7 @@ String? _rootDirPath;
void setRootDirFromEnv() => _rootDirPath = Platform.environment['CAKE_WALLET_DIR'];
Future<Directory> getAppDir({String appName = 'cake_wallet'}) async {
Future<Directory> getAppDir({String appName = 'cake_wallet', required bool isFlatpak}) async {
Directory dir;
if (_rootDirPath != null && _rootDirPath!.isNotEmpty) {
@ -13,13 +13,23 @@ Future<Directory> getAppDir({String appName = 'cake_wallet'}) async {
dir.create(recursive: true);
} else {
if (Platform.isLinux) {
String appDirPath;
String appDirPath = '';
try {
dir = await getApplicationDocumentsDirectory();
appDirPath = '${dir.path}/$appName';
} catch (e) {
appDirPath = '/home/${Platform.environment['USER']}/.$appName';
if (isFlatpak) {
appDirPath =
'/home/${Platform.environment['USER']}/.var/app/com.cakewallet.CakeWallet/data/.$appName';
} else {
final homePath = '/home/${Platform.environment['USER']}/.$appName';
if (await Directory(homePath).exists()) {
appDirPath = homePath;
} else {
final docPath = await getApplicationDocumentsDirectory();
if (await docPath.exists()) {
appDirPath = docPath.path;
}
}
}
dir = Directory.fromUri(Uri.file(appDirPath));

View file

@ -19,12 +19,14 @@ abstract class EthereumTransactionHistoryBase
required this.walletInfo,
required String password,
required this.encryptionFileUtils,
required this.isFlatpak,
}) : _password = password {
transactions = ObservableMap<String, EthereumTransactionInfo>();
}
final WalletInfo walletInfo;
final EncryptionFileUtils encryptionFileUtils;
final bool isFlatpak;
String _password;
Future<void> init() async => await _load();
@ -32,7 +34,8 @@ abstract class EthereumTransactionHistoryBase
@override
Future<void> save() async {
try {
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
final dirPath = await pathForWalletDir(
name: walletInfo.name, type: walletInfo.type, isFlatpak: isFlatpak);
final path = '$dirPath/$transactionsHistoryFileName';
final data = json.encode({'transactions': transactions});
await encryptionFileUtils.write(path: path, password: _password, data: data);
@ -50,7 +53,8 @@ abstract class EthereumTransactionHistoryBase
this.transactions.addAll(transactions);
Future<Map<String, dynamic>> _read() async {
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
final dirPath =
await pathForWalletDir(name: walletInfo.name, type: walletInfo.type, isFlatpak: isFlatpak);
final path = '$dirPath/$transactionsHistoryFileName';
final content = await encryptionFileUtils.read(path: path, password: _password);
if (content.isEmpty) {

View file

@ -50,6 +50,7 @@ abstract class EthereumWalletBase
required String password,
required EncryptionFileUtils encryptionFileUtils,
ERC20Balance? initialBalance,
required this.isFlatpak,
}) : syncStatus = NotConnectedSyncStatus(),
_password = password,
_mnemonic = mnemonic,
@ -75,6 +76,8 @@ abstract class EthereumWalletBase
_sharedPrefs.complete(SharedPreferences.getInstance());
}
final bool isFlatpak;
final String? _mnemonic;
final String? _hexPrivateKey;
final String _password;
@ -374,7 +377,8 @@ abstract class EthereumWalletBase
}
}
Future<String> makePath() async => pathForWallet(name: walletInfo.name, type: walletInfo.type);
Future<String> makePath() async =>
pathForWallet(name: walletInfo.name, type: walletInfo.type, isFlatpak: isFlatpak);
String toJSON() => json.encode({
'mnemonic': _mnemonic,
@ -387,8 +391,9 @@ abstract class EthereumWalletBase
required String password,
required WalletInfo walletInfo,
required EncryptionFileUtils encryptionFileUtils,
required bool isFlatpak,
}) async {
final path = await pathForWallet(name: name, type: walletInfo.type);
final path = await pathForWallet(name: name, type: walletInfo.type, isFlatpak: isFlatpak);
final jsonSource = await encryptionFileUtils.read(path: path, password: password);
final data = json.decode(jsonSource) as Map;
final mnemonic = data['mnemonic'] as String?;
@ -508,19 +513,23 @@ abstract class EthereumWalletBase
@override
Future<void> renameWalletFiles(String newWalletName) async {
final currentWalletPath = await pathForWallet(name: walletInfo.name, type: type);
final currentWalletPath =
await pathForWallet(name: walletInfo.name, type: type, isFlatpak: isFlatpak);
final currentWalletFile = File(currentWalletPath);
final currentDirPath = await pathForWalletDir(name: walletInfo.name, type: type);
final currentDirPath =
await pathForWalletDir(name: walletInfo.name, type: type, isFlatpak: isFlatpak);
final currentTransactionsFile = File('$currentDirPath/$transactionsHistoryFileName');
// Copies current wallet files into new wallet name's dir and files
if (currentWalletFile.existsSync()) {
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
final newWalletPath =
await pathForWallet(name: newWalletName, type: type, isFlatpak: isFlatpak);
await currentWalletFile.copy(newWalletPath);
}
if (currentTransactionsFile.existsSync()) {
final newDirPath = await pathForWalletDir(name: newWalletName, type: type);
final newDirPath =
await pathForWalletDir(name: newWalletName, type: type, isFlatpak: isFlatpak);
await currentTransactionsFile.copy('$newDirPath/$transactionsHistoryFileName');
}

View file

@ -15,10 +15,11 @@ import 'package:collection/collection.dart';
class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
EthereumRestoreWalletFromSeedCredentials, EthereumRestoreWalletFromPrivateKey> {
EthereumWalletService(this.walletInfoSource, this.isDirect);
EthereumWalletService(this.walletInfoSource, this.isDirect, this.isFlatpak);
final Box<WalletInfo> walletInfoSource;
final bool isDirect;
final bool isFlatpak;
@override
Future<EthereumWallet> create(EthereumNewWalletCredentials credentials) async {
@ -30,6 +31,7 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
mnemonic: mnemonic,
password: credentials.password!,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.init();
@ -44,7 +46,7 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
@override
Future<bool> isWalletExit(String name) async =>
File(await pathForWallet(name: name, type: getType())).existsSync();
File(await pathForWallet(name: name, type: getType(), isFlatpak: isFlatpak)).existsSync();
@override
Future<EthereumWallet> openWallet(String name, String password) async {
@ -55,6 +57,7 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
password: password,
walletInfo: walletInfo,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.init();
@ -65,7 +68,8 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
File(await pathForWalletDir(name: wallet, type: getType(), isFlatpak: isFlatpak))
.delete(recursive: true);
final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
await walletInfoSource.delete(walletInfo.key);
@ -78,6 +82,7 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
privateKey: credentials.privateKey,
walletInfo: credentials.walletInfo!,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.init();
@ -99,6 +104,7 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.init();
@ -117,6 +123,7 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
name: currentName,
walletInfo: currentWalletInfo,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await currentWallet.renameWalletFiles(newName);

View file

@ -41,12 +41,14 @@ const moneroBlockSize = 1000;
class MoneroWallet = MoneroWalletBase with _$MoneroWallet;
abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
MoneroTransactionHistory, MoneroTransactionInfo> with Store {
MoneroWalletBase({required WalletInfo walletInfo,
abstract class MoneroWalletBase
extends WalletBase<MoneroBalance, MoneroTransactionHistory, MoneroTransactionInfo> with Store {
MoneroWalletBase({
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required String password})
: balance = ObservableMap<CryptoCurrency, MoneroBalance>.of({
required String password,
required this.isFlatpak,
}) : balance = ObservableMap<CryptoCurrency, MoneroBalance>.of({
CryptoCurrency.xmr: MoneroBalance(
fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
unlockedBalance: monero_wallet.getFullBalance(accountIndex: 0))
@ -79,6 +81,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
});
}
final bool isFlatpak;
static const int _autoSaveInterval = 30;
Box<UnspentCoinsInfo> unspentCoinsInfo;
@ -315,18 +319,21 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
}
await walletAddresses.updateAddressesInBox();
await backupWalletFiles(name);
await backupWalletFiles(name, isFlatpak);
await monero_wallet.store();
}
@override
Future<void> renameWalletFiles(String newWalletName) async {
final currentWalletDirPath = await pathForWalletDir(name: name, type: type);
final currentWalletDirPath =
await pathForWalletDir(name: name, type: type, isFlatpak: isFlatpak);
try {
// -- rename the waller folder --
final currentWalletDir = Directory(await pathForWalletDir(name: name, type: type));
final newWalletDirPath = await pathForWalletDir(name: newWalletName, type: type);
final currentWalletDir =
Directory(await pathForWalletDir(name: name, type: type, isFlatpak: isFlatpak));
final newWalletDirPath =
await pathForWalletDir(name: newWalletName, type: type, isFlatpak: isFlatpak);
await currentWalletDir.rename(newWalletDirPath);
// -- use new waller folder to rename files with old names still --
@ -336,7 +343,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
final currentKeysFile = File('$renamedWalletPath.keys');
final currentAddressListFile = File('$renamedWalletPath.address.txt');
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
final newWalletPath =
await pathForWallet(name: newWalletName, type: type, isFlatpak: isFlatpak);
if (currentCacheFile.existsSync()) {
await currentCacheFile.rename(newWalletPath);
@ -348,13 +356,14 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
await currentAddressListFile.rename('$newWalletPath.address.txt');
}
} catch (e) {
final currentWalletPath = await pathForWallet(name: name, type: type);
final currentWalletPath = await pathForWallet(name: name, type: type, isFlatpak: isFlatpak);
final currentCacheFile = File(currentWalletPath);
final currentKeysFile = File('$currentWalletPath.keys');
final currentAddressListFile = File('$currentWalletPath.address.txt');
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
final newWalletPath =
await pathForWallet(name: newWalletName, type: type, isFlatpak: isFlatpak);
// Copies current wallet files into new wallet name's dir and files
if (currentCacheFile.existsSync()) {
@ -413,9 +422,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
if (coin.spent == 0) {
final unspent = MoneroUnspent.fromCoinsInfoRow(coin);
if (unspent.hash.isNotEmpty) {
unspent.isChange = transaction_history
.getTransaction(unspent.hash)
.direction == 1;
unspent.isChange = transaction_history.getTransaction(unspent.hash).direction == 1;
}
unspentCoins.add(unspent);
}
@ -429,7 +436,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
if (unspentCoins.isNotEmpty) {
unspentCoins.forEach((coin) {
final coinInfoList = unspentCoinsInfo.values.where((element) =>
element.walletId.contains(id) &&
element.walletId.contains(id) &&
element.accountIndex == walletAddresses.account!.id &&
element.keyImage!.contains(coin.keyImage!));

View file

@ -15,7 +15,8 @@ import 'package:hive/hive.dart';
import 'package:polyseed/polyseed.dart';
class MoneroNewWalletCredentials extends WalletCredentials {
MoneroNewWalletCredentials({required String name, required this.language, required this.isPolyseed, String? password})
MoneroNewWalletCredentials(
{required String name, required this.language, required this.isPolyseed, String? password})
: super(name: name, password: password);
final String language;
@ -52,14 +53,13 @@ class MoneroRestoreWalletFromKeysCredentials extends WalletCredentials {
final String spendKey;
}
class MoneroWalletService extends WalletService<
MoneroNewWalletCredentials,
MoneroRestoreWalletFromSeedCredentials,
MoneroRestoreWalletFromKeysCredentials> {
MoneroWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
class MoneroWalletService extends WalletService<MoneroNewWalletCredentials,
MoneroRestoreWalletFromSeedCredentials, MoneroRestoreWalletFromKeysCredentials> {
MoneroWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.isFlatpak);
final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
final bool isFlatpak;
static bool walletFilesExist(String path) =>
!File(path).existsSync() && !File('$path.keys').existsSync();
@ -70,7 +70,8 @@ class MoneroWalletService extends WalletService<
@override
Future<MoneroWallet> create(MoneroNewWalletCredentials credentials) async {
try {
final path = await pathForWallet(name: credentials.name, type: getType());
final path =
await pathForWallet(name: credentials.name, type: getType(), isFlatpak: isFlatpak);
if (credentials.isPolyseed) {
final polyseed = Polyseed.create();
@ -89,7 +90,9 @@ class MoneroWalletService extends WalletService<
final wallet = MoneroWallet(
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
password: credentials.password!);
password: credentials.password!,
isFlatpak: isFlatpak,
);
await wallet.init();
return wallet;
@ -103,7 +106,7 @@ class MoneroWalletService extends WalletService<
@override
Future<bool> isWalletExit(String name) async {
try {
final path = await pathForWallet(name: name, type: getType());
final path = await pathForWallet(name: name, type: getType(), isFlatpak: isFlatpak);
return monero_wallet_manager.isWalletExist(path: path);
} catch (e) {
// TODO: Implement Exception for wallet list service.
@ -115,24 +118,24 @@ class MoneroWalletService extends WalletService<
@override
Future<MoneroWallet> openWallet(String name, String password) async {
try {
final path = await pathForWallet(name: name, type: getType());
final path = await pathForWallet(name: name, type: getType(), isFlatpak: isFlatpak);
if (walletFilesExist(path)) {
await repairOldAndroidWallet(name);
}
await monero_wallet_manager
.openWalletAsync({'path': path, 'password': password});
final walletInfo = walletInfoSource.values.firstWhere(
(info) => info.id == WalletBase.idFor(name, getType()));
await monero_wallet_manager.openWalletAsync({'path': path, 'password': password});
final walletInfo = walletInfoSource.values
.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
final wallet = MoneroWallet(
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
password: password);
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
password: password,
isFlatpak: isFlatpak);
final isValid = wallet.walletAddresses.validate();
if (!isValid) {
await restoreOrResetWalletFiles(name);
await restoreOrResetWalletFiles(name, isFlatpak);
wallet.close();
return openWallet(name, password);
}
@ -166,7 +169,7 @@ class MoneroWalletService extends WalletService<
isMissingCacheFilesIOS ||
isMissingCacheFilesAndroid ||
invalidSignature) {
await restoreOrResetWalletFiles(name);
await restoreOrResetWalletFiles(name, isFlatpak);
return openWallet(name, password);
}
@ -176,7 +179,7 @@ class MoneroWalletService extends WalletService<
@override
Future<void> remove(String wallet) async {
final path = await pathForWalletDir(name: wallet, type: getType());
final path = await pathForWalletDir(name: wallet, type: getType(), isFlatpak: isFlatpak);
final file = Directory(path);
final isExist = file.existsSync();
@ -190,14 +193,14 @@ class MoneroWalletService extends WalletService<
}
@override
Future<void> rename(
String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values.firstWhere(
(info) => info.id == WalletBase.idFor(currentName, getType()));
Future<void> rename(String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
final currentWallet = MoneroWallet(
walletInfo: currentWalletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
password: password,
isFlatpak: isFlatpak,
);
await currentWallet.renameWalletFiles(newName);
@ -210,10 +213,10 @@ class MoneroWalletService extends WalletService<
}
@override
Future<MoneroWallet> restoreFromKeys(
MoneroRestoreWalletFromKeysCredentials credentials) async {
Future<MoneroWallet> restoreFromKeys(MoneroRestoreWalletFromKeysCredentials credentials) async {
try {
final path = await pathForWallet(name: credentials.name, type: getType());
final path =
await pathForWallet(name: credentials.name, type: getType(), isFlatpak: isFlatpak);
await monero_wallet_manager.restoreFromKeys(
path: path,
password: credentials.password!,
@ -225,7 +228,9 @@ class MoneroWalletService extends WalletService<
final wallet = MoneroWallet(
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
password: credentials.password!);
password: credentials.password!,
isFlatpak: isFlatpak,
);
await wallet.init();
return wallet;
@ -237,16 +242,15 @@ class MoneroWalletService extends WalletService<
}
@override
Future<MoneroWallet> restoreFromSeed(
MoneroRestoreWalletFromSeedCredentials credentials) async {
Future<MoneroWallet> restoreFromSeed(MoneroRestoreWalletFromSeedCredentials credentials) async {
// Restore from Polyseed
if (Polyseed.isValidSeed(credentials.mnemonic)) {
return restoreFromPolyseed(credentials);
}
try {
final path = await pathForWallet(name: credentials.name, type: getType());
final path =
await pathForWallet(name: credentials.name, type: getType(), isFlatpak: isFlatpak);
await monero_wallet_manager.restoreFromSeed(
path: path,
password: credentials.password!,
@ -255,7 +259,9 @@ class MoneroWalletService extends WalletService<
final wallet = MoneroWallet(
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource,
password: credentials.password!);
password: credentials.password!,
isFlatpak: isFlatpak,
);
await wallet.init();
return wallet;
@ -266,14 +272,17 @@ class MoneroWalletService extends WalletService<
}
}
Future<MoneroWallet> restoreFromPolyseed(MoneroRestoreWalletFromSeedCredentials credentials) async {
Future<MoneroWallet> restoreFromPolyseed(
MoneroRestoreWalletFromSeedCredentials credentials) async {
try {
final path = await pathForWallet(name: credentials.name, type: getType());
final path =
await pathForWallet(name: credentials.name, type: getType(), isFlatpak: isFlatpak);
final polyseedCoin = PolyseedCoin.POLYSEED_MONERO;
final lang = PolyseedLang.getByPhrase(credentials.mnemonic);
final polyseed = Polyseed.decode(credentials.mnemonic, lang, polyseedCoin);
return _restoreFromPolyseed(path, credentials.password!, polyseed, credentials.walletInfo!, lang);
return _restoreFromPolyseed(
path, credentials.password!, polyseed, credentials.walletInfo!, lang);
} catch (e) {
// TODO: Implement Exception for wallet list service.
print('MoneroWalletsManager Error: $e');
@ -281,11 +290,11 @@ class MoneroWalletService extends WalletService<
}
}
Future<MoneroWallet> _restoreFromPolyseed(String path, String password, Polyseed polyseed,
WalletInfo walletInfo, PolyseedLang lang,
Future<MoneroWallet> _restoreFromPolyseed(
String path, String password, Polyseed polyseed, WalletInfo walletInfo, PolyseedLang lang,
{PolyseedCoin coin = PolyseedCoin.POLYSEED_MONERO, int? overrideHeight}) async {
final height = overrideHeight ?? getMoneroHeigthByDate(
date: DateTime.fromMillisecondsSinceEpoch(polyseed.birthday * 1000));
final height = overrideHeight ??
getMoneroHeigthByDate(date: DateTime.fromMillisecondsSinceEpoch(polyseed.birthday * 1000));
final spendKey = polyseed.generateKey(coin, 32).toHexString();
final seed = polyseed.encode(lang, coin);
@ -304,6 +313,7 @@ class MoneroWalletService extends WalletService<
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource,
password: password,
isFlatpak: isFlatpak,
);
await wallet.init();
@ -317,7 +327,7 @@ class MoneroWalletService extends WalletService<
}
final oldAndroidWalletDirPath =
await outdatedAndroidPathForWalletDir(name: name);
await outdatedAndroidPathForWalletDir(name: name, isFlatpak: isFlatpak);
final dir = Directory(oldAndroidWalletDirPath);
if (!dir.existsSync()) {
@ -325,7 +335,7 @@ class MoneroWalletService extends WalletService<
}
final newWalletDirPath =
await pathForWalletDir(name: name, type: getType());
await pathForWalletDir(name: name, type: getType(), isFlatpak: isFlatpak);
dir.listSync().forEach((f) {
final file = File(f.path);

View file

@ -19,6 +19,7 @@ abstract class NanoTransactionHistoryBase extends TransactionHistoryBase<NanoTra
required this.walletInfo,
required String password,
required this.encryptionFileUtils,
required this.isFlatpak,
}) : _password = password {
transactions = ObservableMap<String, NanoTransactionInfo>();
}
@ -26,13 +27,15 @@ abstract class NanoTransactionHistoryBase extends TransactionHistoryBase<NanoTra
final WalletInfo walletInfo;
final EncryptionFileUtils encryptionFileUtils;
String _password;
final bool isFlatpak;
Future<void> init() async => await _load();
@override
Future<void> save() async {
try {
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
final dirPath = await pathForWalletDir(
name: walletInfo.name, type: walletInfo.type, isFlatpak: isFlatpak);
final path = '$dirPath/$transactionsHistoryFileName';
final data = json.encode({'transactions': transactions});
await encryptionFileUtils.write(path: path, password: _password, data: data);
@ -49,7 +52,8 @@ abstract class NanoTransactionHistoryBase extends TransactionHistoryBase<NanoTra
this.transactions.addAll(transactions);
Future<Map<String, dynamic>> _read() async {
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
final dirPath =
await pathForWalletDir(name: walletInfo.name, type: walletInfo.type, isFlatpak: isFlatpak);
final path = '$dirPath/$transactionsHistoryFileName';
final content = await encryptionFileUtils.read(path: path, password: _password);
if (content.isEmpty) {

View file

@ -40,6 +40,7 @@ abstract class NanoWalletBase
required String password,
NanoBalance? initialBalance,
required EncryptionFileUtils encryptionFileUtils,
required this.isFlatpak,
}) : syncStatus = NotConnectedSyncStatus(),
_password = password,
_mnemonic = mnemonic,
@ -64,6 +65,8 @@ abstract class NanoWalletBase
}
}
final bool isFlatpak;
String _mnemonic;
final String _password;
DerivationType _derivationType;
@ -366,7 +369,8 @@ abstract class NanoWalletBase
}
}
Future<String> makePath() async => pathForWallet(name: walletInfo.name, type: walletInfo.type);
Future<String> makePath() async =>
pathForWallet(name: walletInfo.name, type: walletInfo.type, isFlatpak: isFlatpak);
String toJSON() => json.encode({
'seedKey': _hexSeed,
@ -376,13 +380,13 @@ abstract class NanoWalletBase
'derivationType': _derivationType.toString()
});
static Future<NanoWallet> open({
required String name,
required String password,
required WalletInfo walletInfo,
required EncryptionFileUtils encryptionFileUtils,
}) async {
final path = await pathForWallet(name: name, type: walletInfo.type);
static Future<NanoWallet> open(
{required String name,
required String password,
required WalletInfo walletInfo,
required EncryptionFileUtils encryptionFileUtils,
required bool isFlatpak}) async {
final path = await pathForWallet(name: name, type: walletInfo.type, isFlatpak: isFlatpak);
final jsonSource = await encryptionFileUtils.read(path: path, password: password);
final data = json.decode(jsonSource) as Map;
@ -482,19 +486,23 @@ abstract class NanoWalletBase
@override
Future<void> renameWalletFiles(String newWalletName) async {
final currentWalletPath = await pathForWallet(name: walletInfo.name, type: type);
final currentWalletPath =
await pathForWallet(name: walletInfo.name, type: type, isFlatpak: isFlatpak);
final currentWalletFile = File(currentWalletPath);
final currentDirPath = await pathForWalletDir(name: walletInfo.name, type: type);
final currentDirPath =
await pathForWalletDir(name: walletInfo.name, type: type, isFlatpak: isFlatpak);
final currentTransactionsFile = File('$currentDirPath/$transactionsHistoryFileName');
// Copies current wallet files into new wallet name's dir and files
if (currentWalletFile.existsSync()) {
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
final newWalletPath =
await pathForWallet(name: newWalletName, type: type, isFlatpak: isFlatpak);
await currentWalletFile.copy(newWalletPath);
}
if (currentTransactionsFile.existsSync()) {
final newDirPath = await pathForWalletDir(name: newWalletName, type: type);
final newDirPath =
await pathForWalletDir(name: newWalletName, type: type, isFlatpak: isFlatpak);
await currentTransactionsFile.copy('$newDirPath/$transactionsHistoryFileName');
}

View file

@ -16,10 +16,11 @@ import 'package:nanoutil/nanoutil.dart';
class NanoWalletService extends WalletService<NanoNewWalletCredentials,
NanoRestoreWalletFromSeedCredentials, NanoRestoreWalletFromKeysCredentials> {
NanoWalletService(this.walletInfoSource, this.isDirect);
NanoWalletService(this.walletInfoSource, this.isDirect, this.isFlatpak);
final Box<WalletInfo> walletInfoSource;
final bool isDirect;
final bool isFlatpak;
static bool walletFilesExist(String path) =>
!File(path).existsSync() && !File('$path.keys').existsSync();
@ -41,6 +42,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
mnemonic: mnemonic,
password: credentials.password!,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
wallet.init();
return wallet;
@ -48,7 +50,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
@override
Future<void> remove(String wallet) async {
final path = await pathForWalletDir(name: wallet, type: getType());
final path = await pathForWalletDir(name: wallet, type: getType(), isFlatpak: isFlatpak);
final file = Directory(path);
final isExist = file.existsSync();
@ -73,6 +75,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
password: password,
mnemonic: randomWords,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await currentWallet.renameWalletFiles(newName);
@ -113,6 +116,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
mnemonic: mnemonic ?? credentials.seedKey,
walletInfo: credentials.walletInfo!,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.init();
await wallet.save();
@ -144,6 +148,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.init();
@ -153,7 +158,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
@override
Future<bool> isWalletExit(String name) async =>
File(await pathForWallet(name: name, type: getType())).existsSync();
File(await pathForWallet(name: name, type: getType(), isFlatpak: isFlatpak)).existsSync();
@override
Future<NanoWallet> openWallet(String name, String password) async {
@ -164,6 +169,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
password: password,
walletInfo: walletInfo,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
isFlatpak: isFlatpak,
);
await wallet.init();

View file

@ -15,11 +15,13 @@ class PolygonTransactionHistory = PolygonTransactionHistoryBase with _$PolygonTr
abstract class PolygonTransactionHistoryBase extends TransactionHistoryBase<PolygonTransactionInfo>
with Store {
PolygonTransactionHistoryBase({required this.walletInfo, required String password})
PolygonTransactionHistoryBase(
{required this.walletInfo, required String password, required this.isFlatpak})
: _password = password {
transactions = ObservableMap<String, PolygonTransactionInfo>();
}
final bool isFlatpak;
final WalletInfo walletInfo;
String _password;
@ -28,7 +30,8 @@ abstract class PolygonTransactionHistoryBase extends TransactionHistoryBase<Poly
@override
Future<void> save() async {
try {
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
final dirPath = await pathForWalletDir(
name: walletInfo.name, type: walletInfo.type, isFlatpak: isFlatpak);
final path = '$dirPath/$transactionsHistoryFileName';
final data = json.encode({'transactions': transactions});
await writeData(path: path, password: _password, data: data);
@ -46,7 +49,8 @@ abstract class PolygonTransactionHistoryBase extends TransactionHistoryBase<Poly
this.transactions.addAll(transactions);
Future<Map<String, dynamic>> _read() async {
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
final dirPath =
await pathForWalletDir(name: walletInfo.name, type: walletInfo.type, isFlatpak: isFlatpak);
final path = '$dirPath/$transactionsHistoryFileName';
final content = await read(path: path, password: _password);
if (content.isEmpty) {

View file

@ -49,6 +49,7 @@ abstract class PolygonWalletBase
String? privateKey,
required String password,
ERC20Balance? initialBalance,
required this.isFlatpak,
}) : syncStatus = const NotConnectedSyncStatus(),
_password = password,
_mnemonic = mnemonic,
@ -69,6 +70,8 @@ abstract class PolygonWalletBase
_sharedPrefs.complete(SharedPreferences.getInstance());
}
final bool isFlatpak;
final String? _mnemonic;
final String? _hexPrivateKey;
final String _password;
@ -342,7 +345,8 @@ abstract class PolygonWalletBase
}
}
Future<String> makePath() async => pathForWallet(name: walletInfo.name, type: walletInfo.type);
Future<String> makePath() async =>
pathForWallet(name: walletInfo.name, type: walletInfo.type, isFlatpak: isFlatpak);
String toJSON() => json.encode({
'mnemonic': _mnemonic,
@ -350,12 +354,12 @@ abstract class PolygonWalletBase
'balance': balance[currency]!.toJSON(),
});
static Future<PolygonWallet> open({
required String name,
required String password,
required WalletInfo walletInfo,
}) async {
final path = await pathForWallet(name: name, type: walletInfo.type);
static Future<PolygonWallet> open(
{required String name,
required String password,
required WalletInfo walletInfo,
required bool isFlatpak}) async {
final path = await pathForWallet(name: name, type: walletInfo.type, isFlatpak: isFlatpak);
final jsonSource = await read(path: path, password: password);
final data = json.decode(jsonSource) as Map;
final mnemonic = data['mnemonic'] as String?;
@ -477,19 +481,23 @@ abstract class PolygonWalletBase
@override
Future<void> renameWalletFiles(String newWalletName) async {
final currentWalletPath = await pathForWallet(name: walletInfo.name, type: type);
final currentWalletPath =
await pathForWallet(name: walletInfo.name, type: type, isFlatpak: isFlatpak);
final currentWalletFile = File(currentWalletPath);
final currentDirPath = await pathForWalletDir(name: walletInfo.name, type: type);
final currentDirPath =
await pathForWalletDir(name: walletInfo.name, type: type, isFlatpak: isFlatpak);
final currentTransactionsFile = File('$currentDirPath/$transactionsHistoryFileName');
// Copies current wallet files into new wallet name's dir and files
if (currentWalletFile.existsSync()) {
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
final newWalletPath =
await pathForWallet(name: newWalletName, type: type, isFlatpak: isFlatpak);
await currentWalletFile.copy(newWalletPath);
}
if (currentTransactionsFile.existsSync()) {
final newDirPath = await pathForWalletDir(name: newWalletName, type: type);
final newDirPath =
await pathForWalletDir(name: newWalletName, type: type, isFlatpak: isFlatpak);
await currentTransactionsFile.copy('$newDirPath/$transactionsHistoryFileName');
}

View file

@ -14,9 +14,10 @@ import 'package:collection/collection.dart';
class PolygonWalletService extends WalletService<PolygonNewWalletCredentials,
PolygonRestoreWalletFromSeedCredentials, PolygonRestoreWalletFromPrivateKey> {
PolygonWalletService(this.walletInfoSource);
PolygonWalletService(this.walletInfoSource, this.isFlatpak);
final Box<WalletInfo> walletInfoSource;
final bool isFlatpak;
@override
Future<PolygonWallet> create(PolygonNewWalletCredentials credentials) async {
@ -27,6 +28,7 @@ class PolygonWalletService extends WalletService<PolygonNewWalletCredentials,
walletInfo: credentials.walletInfo!,
mnemonic: mnemonic,
password: credentials.password!,
isFlatpak: isFlatpak,
);
await wallet.init();
@ -41,7 +43,7 @@ class PolygonWalletService extends WalletService<PolygonNewWalletCredentials,
@override
Future<bool> isWalletExit(String name) async =>
File(await pathForWallet(name: name, type: getType())).existsSync();
File(await pathForWallet(name: name, type: getType(), isFlatpak: isFlatpak)).existsSync();
@override
Future<PolygonWallet> openWallet(String name, String password) async {
@ -51,6 +53,7 @@ class PolygonWalletService extends WalletService<PolygonNewWalletCredentials,
name: name,
password: password,
walletInfo: walletInfo,
isFlatpak: isFlatpak,
);
await wallet.init();
@ -61,7 +64,8 @@ class PolygonWalletService extends WalletService<PolygonNewWalletCredentials,
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
File(await pathForWalletDir(name: wallet, type: getType(), isFlatpak: isFlatpak))
.delete(recursive: true);
final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
await walletInfoSource.delete(walletInfo.key);
@ -73,6 +77,7 @@ class PolygonWalletService extends WalletService<PolygonNewWalletCredentials,
password: credentials.password!,
privateKey: credentials.privateKey,
walletInfo: credentials.walletInfo!,
isFlatpak: isFlatpak,
);
await wallet.init();
@ -92,6 +97,7 @@ class PolygonWalletService extends WalletService<PolygonNewWalletCredentials,
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
isFlatpak: isFlatpak,
);
await wallet.init();
@ -106,7 +112,11 @@ class PolygonWalletService extends WalletService<PolygonNewWalletCredentials,
final currentWalletInfo = walletInfoSource.values
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
final currentWallet = await PolygonWalletBase.open(
password: password, name: currentName, walletInfo: currentWalletInfo);
password: password,
name: currentName,
walletInfo: currentWalletInfo,
isFlatpak: isFlatpak,
);
await currentWallet.renameWalletFiles(newName);

View file

@ -1,182 +1,286 @@
part of 'bitcoin.dart';
class CWBitcoin extends Bitcoin {
@override
TransactionPriority getMediumTransactionPriority() => BitcoinTransactionPriority.medium;
@override
WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({
required String name,
required String mnemonic,
required String password})
=> BitcoinRestoreWalletFromSeedCredentials(name: name, mnemonic: mnemonic, password: password);
@override
WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({
required String name,
required String password,
required String wif,
WalletInfo? walletInfo})
=> BitcoinRestoreWalletFromWIFCredentials(name: name, password: password, wif: wif, walletInfo: walletInfo);
@override
WalletCredentials createBitcoinNewWalletCredentials({
required String name,
WalletInfo? walletInfo,
String? password})
=> BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
@override
List<String> getWordList() => wordlist;
@override
Map<String, String> getWalletKeys(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
final keys = bitcoinWallet.keys;
return <String, String>{
'wif': keys.wif,
'privateKey': keys.privateKey,
'publicKey': keys.publicKey
};
}
@override
List<TransactionPriority> getTransactionPriorities()
=> BitcoinTransactionPriority.all;
@override
List<TransactionPriority> getLitecoinTransactionPriorities()
=> LitecoinTransactionPriority.all;
@override
TransactionPriority deserializeBitcoinTransactionPriority(int raw)
=> BitcoinTransactionPriority.deserialize(raw: raw);
@override
TransactionPriority deserializeLitecoinTransactionPriority(int raw)
=> LitecoinTransactionPriority.deserialize(raw: raw);
@override
int getFeeRate(Object wallet, TransactionPriority priority) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.feeRate(priority);
}
@override
Future<void> generateNewAddress(Object wallet, String label) async {
final bitcoinWallet = wallet as ElectrumWallet;
await bitcoinWallet.walletAddresses.generateNewAddress(label: label);
await wallet.save();
}
@override
Future<void> updateAddress(Object wallet,String address, String label) async {
final bitcoinWallet = wallet as ElectrumWallet;
bitcoinWallet.walletAddresses.updateAddress(address, label);
await wallet.save();
}
@override
Object createBitcoinTransactionCredentials(List<Output> outputs, {required TransactionPriority priority, int? feeRate})
=> BitcoinTransactionCredentials(
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(),
priority: priority as BitcoinTransactionPriority,
feeRate: feeRate);
@override
Object createBitcoinTransactionCredentialsRaw(List<OutputInfo> outputs, {TransactionPriority? priority, required int feeRate})
=> BitcoinTransactionCredentials(
outputs,
priority: priority != null ? priority as BitcoinTransactionPriority : null,
feeRate: feeRate);
@override
List<String> getAddresses(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.walletAddresses.addresses
.map((BitcoinAddressRecord addr) => addr.address)
.toList();
}
@override
@computed
List<ElectrumSubAddress> getSubAddresses(Object wallet) {
final electrumWallet = wallet as ElectrumWallet;
return electrumWallet.walletAddresses.addresses
.map((BitcoinAddressRecord addr) => ElectrumSubAddress(
id: addr.index,
name: addr.name,
address: electrumWallet.type == WalletType.bitcoinCash ? addr.cashAddr : addr.address,
txCount: addr.txCount,
balance: addr.balance,
isChange: addr.isHidden))
.toList();
}
@override
String getAddress(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.walletAddresses.address;
}
@override
String formatterBitcoinAmountToString({required int amount})
=> bitcoinAmountToString(amount: amount);
@override
double formatterBitcoinAmountToDouble({required int amount})
=> bitcoinAmountToDouble(amount: amount);
@override
int formatterStringDoubleToBitcoinAmount(String amount)
=> stringDoubleToBitcoinAmount(amount);
@override
TransactionPriority getMediumTransactionPriority() => BitcoinTransactionPriority.medium;
@override
String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate)
=> (priority as BitcoinTransactionPriority).labelWithRate(rate);
@override
List<BitcoinUnspent> getUnspents(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.unspentCoins;
}
void updateUnspents(Object wallet) async {
final bitcoinWallet = wallet as ElectrumWallet;
await bitcoinWallet.updateUnspent();
}
WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
return BitcoinWalletService(walletInfoSource, unspentCoinSource, isDirect);
}
WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
return LitecoinWalletService(walletInfoSource, unspentCoinSource, isDirect);
}
@override
TransactionPriority getBitcoinTransactionPriorityMedium()
=> BitcoinTransactionPriority.medium;
WalletCredentials createBitcoinRestoreWalletFromSeedCredentials(
{required String name, required String mnemonic, required String password}) =>
BitcoinRestoreWalletFromSeedCredentials(name: name, mnemonic: mnemonic, password: password);
@override
TransactionPriority getLitecoinTransactionPriorityMedium()
=> LitecoinTransactionPriority.medium;
WalletCredentials createBitcoinRestoreWalletFromWIFCredentials(
{required String name,
required String password,
required String wif,
WalletInfo? walletInfo}) =>
BitcoinRestoreWalletFromWIFCredentials(
name: name, password: password, wif: wif, walletInfo: walletInfo);
@override
TransactionPriority getBitcoinTransactionPrioritySlow()
=> BitcoinTransactionPriority.slow;
WalletCredentials createBitcoinNewWalletCredentials(
{required String name, WalletInfo? walletInfo, String? password}) =>
BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
@override
TransactionPriority getLitecoinTransactionPrioritySlow()
=> LitecoinTransactionPriority.slow;
}
List<String> getWordList() => wordlist;
@override
Map<String, String> getWalletKeys(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
final keys = bitcoinWallet.keys;
return <String, String>{
'wif': keys.wif,
'privateKey': keys.privateKey,
'publicKey': keys.publicKey
};
}
@override
List<TransactionPriority> getTransactionPriorities() => BitcoinTransactionPriority.all;
@override
List<TransactionPriority> getLitecoinTransactionPriorities() => LitecoinTransactionPriority.all;
@override
TransactionPriority deserializeBitcoinTransactionPriority(int raw) =>
BitcoinTransactionPriority.deserialize(raw: raw);
@override
TransactionPriority deserializeLitecoinTransactionPriority(int raw) =>
LitecoinTransactionPriority.deserialize(raw: raw);
@override
int getFeeRate(Object wallet, TransactionPriority priority) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.feeRate(priority);
}
@override
Future<void> generateNewAddress(Object wallet, String label) async {
final bitcoinWallet = wallet as ElectrumWallet;
await bitcoinWallet.walletAddresses.generateNewAddress(label: label);
await wallet.save();
}
@override
Future<void> updateAddress(Object wallet, String address, String label) async {
final bitcoinWallet = wallet as ElectrumWallet;
bitcoinWallet.walletAddresses.updateAddress(address, label);
await wallet.save();
}
@override
Object createBitcoinTransactionCredentials(List<Output> outputs,
{required TransactionPriority priority, int? feeRate}) =>
BitcoinTransactionCredentials(
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(),
priority: priority as BitcoinTransactionPriority,
feeRate: feeRate);
@override
Object createBitcoinTransactionCredentialsRaw(List<OutputInfo> outputs,
{TransactionPriority? priority, required int feeRate}) =>
BitcoinTransactionCredentials(outputs,
priority: priority != null ? priority as BitcoinTransactionPriority : null,
feeRate: feeRate);
@override
List<String> getAddresses(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.walletAddresses.addresses
.map((BitcoinAddressRecord addr) => addr.address)
.toList();
}
@override
@computed
List<ElectrumSubAddress> getSubAddresses(Object wallet) {
final electrumWallet = wallet as ElectrumWallet;
return electrumWallet.walletAddresses.addresses
.map((BitcoinAddressRecord addr) => ElectrumSubAddress(
id: addr.index,
name: addr.name,
address: electrumWallet.type == WalletType.bitcoinCash ? addr.cashAddr : addr.address,
txCount: addr.txCount,
balance: addr.balance,
isChange: addr.isHidden))
.toList();
}
@override
String getAddress(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.walletAddresses.address;
}
@override
String formatterBitcoinAmountToString({required int amount}) =>
bitcoinAmountToString(amount: amount);
@override
double formatterBitcoinAmountToDouble({required int amount}) =>
bitcoinAmountToDouble(amount: amount);
@override
int formatterStringDoubleToBitcoinAmount(String amount) => stringDoubleToBitcoinAmount(amount);
@override
WalletCredentials createBitcoinRestoreWalletFromSeedCredentials(
{required String name, required String mnemonic, required String password}) =>
BitcoinRestoreWalletFromSeedCredentials(name: name, mnemonic: mnemonic, password: password);
@override
WalletCredentials createBitcoinRestoreWalletFromWIFCredentials(
{required String name,
required String password,
required String wif,
WalletInfo? walletInfo}) =>
BitcoinRestoreWalletFromWIFCredentials(
name: name, password: password, wif: wif, walletInfo: walletInfo);
@override
WalletCredentials createBitcoinNewWalletCredentials(
{required String name, WalletInfo? walletInfo, String? password}) =>
BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
@override
List<String> getWordList() => wordlist;
@override
Map<String, String> getWalletKeys(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
final keys = bitcoinWallet.keys;
return <String, String>{
'wif': keys.wif,
'privateKey': keys.privateKey,
'publicKey': keys.publicKey
};
}
@override
List<TransactionPriority> getTransactionPriorities() => BitcoinTransactionPriority.all;
@override
List<TransactionPriority> getLitecoinTransactionPriorities() => LitecoinTransactionPriority.all;
@override
TransactionPriority deserializeBitcoinTransactionPriority(int raw) =>
BitcoinTransactionPriority.deserialize(raw: raw);
@override
TransactionPriority deserializeLitecoinTransactionPriority(int raw) =>
LitecoinTransactionPriority.deserialize(raw: raw);
@override
int getFeeRate(Object wallet, TransactionPriority priority) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.feeRate(priority);
}
@override
Future<void> generateNewAddress(Object wallet) async {
final bitcoinWallet = wallet as ElectrumWallet;
await bitcoinWallet.walletAddresses.generateNewAddress();
}
@override
Object createBitcoinTransactionCredentials(List<Output> outputs,
{required TransactionPriority priority, int? feeRate}) =>
BitcoinTransactionCredentials(
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(),
priority: priority as BitcoinTransactionPriority,
feeRate: feeRate);
@override
Object createBitcoinTransactionCredentialsRaw(List<OutputInfo> outputs,
{TransactionPriority? priority, required int feeRate}) =>
BitcoinTransactionCredentials(outputs,
priority: priority != null ? priority as BitcoinTransactionPriority : null,
feeRate: feeRate);
@override
List<String> getAddresses(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.walletAddresses.addresses
.map((BitcoinAddressRecord addr) => addr.address)
.toList();
}
@override
String getAddress(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.walletAddresses.address;
}
@override
String formatterBitcoinAmountToString({required int amount}) =>
bitcoinAmountToString(amount: amount);
@override
double formatterBitcoinAmountToDouble({required int amount}) =>
bitcoinAmountToDouble(amount: amount);
@override
int formatterStringDoubleToBitcoinAmount(String amount) => stringDoubleToBitcoinAmount(amount);
@override
String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate) =>
(priority as BitcoinTransactionPriority).labelWithRate(rate);
@override
List<BitcoinUnspent> getUnspents(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.unspentCoins;
}
void updateUnspents(Object wallet) async {
final bitcoinWallet = wallet as ElectrumWallet;
await bitcoinWallet.updateUnspent();
}
WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource,
Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect, bool isFlatpak) {
return BitcoinWalletService(walletInfoSource, unspentCoinSource, isDirect, isFlatpak);
}
WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource,
Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect, bool isFlatpak) {
return LitecoinWalletService(walletInfoSource, unspentCoinSource, isDirect, isFlatpak);
}
@override
TransactionPriority getBitcoinTransactionPriorityMedium() => BitcoinTransactionPriority.medium;
@override
TransactionPriority getLitecoinTransactionPriorityMedium() => LitecoinTransactionPriority.medium;
@override
TransactionPriority getBitcoinTransactionPrioritySlow() => BitcoinTransactionPriority.slow;
@override
TransactionPriority getLitecoinTransactionPrioritySlow() => LitecoinTransactionPriority.slow;
}

View file

@ -11,9 +11,9 @@ class CWBitcoinCash extends BitcoinCash {
String getCashAddrFormat(String address) => AddressUtils.getCashAddrFormat(address);
@override
WalletService createBitcoinCashWalletService(
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) {
return BitcoinCashWalletService(walletInfoSource, unspentCoinSource, isDirect);
WalletService createBitcoinCashWalletService(Box<WalletInfo> walletInfoSource,
Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect, bool isFlatpak) {
return BitcoinCashWalletService(walletInfoSource, unspentCoinSource, isDirect, isFlatpak);
}
@override

View file

@ -8,7 +8,6 @@ import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/core/secure_storage.dart';
import 'package:path_provider/path_provider.dart';
import 'package:cryptography/cryptography.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:archive/archive_io.dart';
@ -21,6 +20,7 @@ import 'package:cw_core/wallet_info.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/wallet_types.g.dart';
import 'package:cake_backup/backup.dart' as cake_backup;
import 'package:cake_wallet/core/flatpak.dart';
class BackupService {
BackupService(
@ -76,7 +76,7 @@ class BackupService {
Future<Uint8List> _exportBackupV2(String password) async {
final zipEncoder = ZipFileEncoder();
final appDir = await getAppDir();
final appDir = await getAppDir(isFlatpak: isFlatpak);
final now = DateTime.now();
final tmpDir = Directory('${appDir.path}/~_BACKUP_TMP');
final archivePath = '${tmpDir.path}/backup_${now.toString()}.zip';
@ -115,9 +115,8 @@ class BackupService {
return await _encryptV2(content, password);
}
Future<void> _importBackupV1(Uint8List data, String password,
{required String nonce}) async {
final appDir = await getAppDir();
Future<void> _importBackupV1(Uint8List data, String password, {required String nonce}) async {
final appDir = await getAppDir(isFlatpak: isFlatpak);
final decryptedData = await _decryptV1(data, password, nonce);
final zip = ZipDecoder().decodeBytes(decryptedData);
@ -140,7 +139,7 @@ class BackupService {
}
Future<void> _importBackupV2(Uint8List data, String password) async {
final appDir = await getAppDir();
final appDir = await getAppDir(isFlatpak: isFlatpak);
final decryptedData = await _decryptV2(data, password);
final zip = ZipDecoder().decodeBytes(decryptedData);
@ -173,7 +172,7 @@ class BackupService {
}
Future<Box<WalletInfo>> _reloadHiveWalletInfoBox() async {
final appDir = await getAppDir();
final appDir = await getAppDir(isFlatpak: isFlatpak);
await CakeHive.close();
CakeHive.init(appDir.path);
@ -185,7 +184,7 @@ class BackupService {
}
Future<void> _importPreferencesDump() async {
final appDir = await getAppDir();
final appDir = await getAppDir(isFlatpak: isFlatpak);
final preferencesFile = File('${appDir.path}/~_preferences_dump');
if (!preferencesFile.existsSync()) {
@ -361,9 +360,8 @@ class BackupService {
}
Future<void> _importKeychainDumpV1(String password,
{required String nonce,
String keychainSalt = secrets.backupKeychainSalt}) async {
final appDir = await getAppDir();
{required String nonce, String keychainSalt = secrets.backupKeychainSalt}) async {
final appDir = await getAppDir(isFlatpak: isFlatpak);
final keychainDumpFile = File('${appDir.path}/~_keychain_dump');
final decryptedKeychainDumpFileData =
await _decryptV1(keychainDumpFile.readAsBytesSync(), '$keychainSalt$password', nonce);
@ -391,7 +389,7 @@ class BackupService {
Future<void> _importKeychainDumpV2(String password,
{String keychainSalt = secrets.backupKeychainSalt}) async {
final appDir = await getAppDir();
final appDir = await getAppDir(isFlatpak: isFlatpak);
final keychainDumpFile = File('${appDir.path}/~_keychain_dump');
final decryptedKeychainDumpFileData =
await _decryptV2(keychainDumpFile.readAsBytesSync(), '$keychainSalt$password');

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
import 'package:cake_wallet/core/flatpak.dart';
import 'package:cake_wallet/core/yat_service.dart';
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
@ -862,25 +863,26 @@ Future<void> setup({
case WalletType.haven:
return haven!.createHavenWalletService(_walletInfoSource);
case WalletType.monero:
return monero!.createMoneroWalletService(_walletInfoSource, _unspentCoinsInfoSource);
return monero!
.createMoneroWalletService(_walletInfoSource, _unspentCoinsInfoSource, isFlatpak);
case WalletType.bitcoin:
return bitcoin!.createBitcoinWalletService(_walletInfoSource, _unspentCoinsInfoSource,
SettingsStoreBase.walletPasswordDirectInput);
SettingsStoreBase.walletPasswordDirectInput, isFlatpak);
case WalletType.litecoin:
return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource,
SettingsStoreBase.walletPasswordDirectInput);
SettingsStoreBase.walletPasswordDirectInput, isFlatpak);
case WalletType.ethereum:
return ethereum!.createEthereumWalletService(
_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput, isFlatpak);
case WalletType.bitcoinCash:
return bitcoinCash!.createBitcoinCashWalletService(_walletInfoSource, _unspentCoinsInfoSource,
SettingsStoreBase.walletPasswordDirectInput);
return bitcoinCash!.createBitcoinCashWalletService(_walletInfoSource,
_unspentCoinsInfoSource, SettingsStoreBase.walletPasswordDirectInput, isFlatpak);
case WalletType.nano:
return nano!.createNanoWalletService(
_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput, isFlatpak);
case WalletType.polygon:
return polygon!.createPolygonWalletService(
_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput, isFlatpak);
default:
throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService');
}

View file

@ -20,6 +20,7 @@ import 'package:cw_core/wallet_info.dart';
import 'package:cake_wallet/exchange/trade.dart';
import 'package:encrypt/encrypt.dart' as encrypt;
import 'package:collection/collection.dart';
import 'package:cake_wallet/core/flatpak.dart';
const newCakeWalletMoneroUri = 'xmr-node.cakewallet.com:18081';
const cakeWalletBitcoinElectrumUri = 'electrum.cakewallet.com:50002';
@ -204,7 +205,7 @@ Future<void> defaultSettingsMigration(
Future<void> _validateWalletInfoBoxData(Box<WalletInfo> walletInfoSource) async {
try {
final root = await getAppDir();
final root = await getAppDir(isFlatpak: isFlatpak);
for (var type in WalletType.values) {
if (type == WalletType.none) {
@ -223,7 +224,7 @@ Future<void> _validateWalletInfoBoxData(Box<WalletInfo> walletInfoSource) async
for (var name in walletNames) {
final Directory dir;
try {
dir = Directory(await pathForWalletDir(name: name, type: type));
dir = Directory(await pathForWalletDir(name: name, type: type, isFlatpak: isFlatpak));
} catch (_) {
continue;
}
@ -588,7 +589,7 @@ Future<void> addAddressesForMoneroWallets(Box<WalletInfo> walletInfoSource) asyn
final moneroWalletsInfo = walletInfoSource.values.where((info) => info.type == WalletType.monero);
moneroWalletsInfo.forEach((info) async {
try {
final walletPath = await pathForWallet(name: info.name, type: WalletType.monero);
final walletPath = await pathForWallet(name: info.name, type: WalletType.monero, isFlatpak: isFlatpak);
final addressFilePath = '$walletPath.address.txt';
final addressFile = File(addressFilePath);

View file

@ -4,8 +4,9 @@ class CWEthereum extends Ethereum {
@override
List<String> getEthereumWordList(String language) => EthereumMnemonics.englishWordlist;
WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
EthereumWalletService(walletInfoSource, isDirect);
WalletService createEthereumWalletService(
Box<WalletInfo> walletInfoSource, bool isDirect, bool isFlatpak) =>
EthereumWalletService(walletInfoSource, isDirect, isFlatpak);
@override
WalletCredentials createEthereumNewWalletCredentials({

View file

@ -10,14 +10,12 @@ import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:cw_core/address_info.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cw_core/root_dir.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cw_core/hive_type_ids.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/di.dart';
import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/core/secure_storage.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@ -43,6 +41,7 @@ import 'package:uni_links/uni_links.dart';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cw_core/cake_hive.dart';
import 'package:cake_wallet/core/flatpak.dart';
final navigatorKey = GlobalKey<NavigatorState>();
final rootKey = GlobalKey<RootState>();
@ -74,7 +73,7 @@ Future<void> main() async {
Future<void> initializeAppConfigs() async {
setRootDirFromEnv();
final appDir = await getAppDir();
final appDir = await getAppDir(isFlatpak: isFlatpak);
await CakeHive.close();
CakeHive.init(appDir.path);

View file

@ -224,13 +224,13 @@ class CWMonero extends Monero {
name: name, password: password, height: height, mnemonic: mnemonic);
@override
WalletCredentials createMoneroNewWalletCredentials({
required String name,
required String language,
required bool isPolyseed,
String? password}) =>
WalletCredentials createMoneroNewWalletCredentials(
{required String name,
required String language,
required bool isPolyseed,
String? password}) =>
MoneroNewWalletCredentials(
name: name, password: password, language: language, isPolyseed: isPolyseed);
name: name, password: password, language: language, isPolyseed: isPolyseed);
@override
Map<String, String> getKeys(Object wallet) {
@ -302,9 +302,9 @@ class CWMonero extends Monero {
}
@override
WalletService createMoneroWalletService(
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) =>
MoneroWalletService(walletInfoSource, unspentCoinSource);
WalletService createMoneroWalletService(Box<WalletInfo> walletInfoSource,
Box<UnspentCoinsInfo> unspentCoinSource, bool isFlatpak) =>
MoneroWalletService(walletInfoSource, unspentCoinSource, isFlatpak);
@override
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex) {

View file

@ -75,8 +75,9 @@ class CWNano extends Nano {
}
@override
WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) {
return NanoWalletService(walletInfoSource, isDirect);
WalletService createNanoWalletService(
Box<WalletInfo> walletInfoSource, bool isDirect, bool isFlatpak) {
return NanoWalletService(walletInfoSource, isDirect, isFlatpak);
}
@override
@ -189,7 +190,6 @@ class CWNano extends Nano {
}
class CWNanoUtil extends NanoUtil {
@override
bool isValidBip39Seed(String seed) {
return NanoDerivations.isValidBip39Seed(seed);

View file

@ -4,15 +4,13 @@ class CWPolygon extends Polygon {
@override
List<String> getPolygonWordList(String language) => EthereumMnemonics.englishWordlist;
WalletService createPolygonWalletService(Box<WalletInfo> walletInfoSource, bool isDirect) =>
PolygonWalletService(walletInfoSource);
WalletService createPolygonWalletService(
Box<WalletInfo> walletInfoSource, bool isDirec, bool isFlatpak) =>
PolygonWalletService(walletInfoSource, isFlatpak);
@override
WalletCredentials createPolygonNewWalletCredentials({
required String name,
WalletInfo? walletInfo,
String? password
}) =>
WalletCredentials createPolygonNewWalletCredentials(
{required String name, WalletInfo? walletInfo, String? password}) =>
PolygonNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
@override

View file

@ -11,7 +11,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mailer/flutter_mailer.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'package:cake_wallet/core/flatpak.dart';
import 'package:shared_preferences/shared_preferences.dart';
class ExceptionHandler {
@ -19,7 +19,7 @@ class ExceptionHandler {
static const _coolDownDurationInDays = 7;
static void _saveException(String? error, StackTrace? stackTrace, {String? library}) async {
final appDocDir = await getAppDir();
final appDocDir = await getAppDir(isFlatpak: isFlatpak);
final file = File('${appDocDir.path}/error.txt');
final exception = {
@ -49,7 +49,7 @@ class ExceptionHandler {
static void _sendExceptionFile() async {
try {
final appDocDir = await getAppDir();
final appDocDir = await getAppDir(isFlatpak: isFlatpak);
final file = File('${appDocDir.path}/error.txt');

View file

@ -10,6 +10,7 @@ import 'package:mobx/mobx.dart';
import 'package:intl/intl.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:path_provider/path_provider.dart';
import 'package:cake_wallet/core/flatpak.dart';
part 'backup_view_model.g.dart';
@ -74,7 +75,7 @@ abstract class BackupViewModelBase with Store {
}
Future<String> saveBackupFileLocally(BackupExportFile backup) async {
final appDir = await getAppDir();
final appDir = await getAppDir(isFlatpak: isFlatpak);
final path = '${appDir.path}/${backup.name}';
final backupFile = File(path);
await backupFile.writeAsBytes(backup.content);
@ -82,7 +83,7 @@ abstract class BackupViewModelBase with Store {
}
Future<void> removeBackupFileLocally(BackupExportFile backup) async {
final appDir = await getAppDir();
final appDir = await getAppDir(isFlatpak: isFlatpak);
final path = '${appDir.path}/${backup.name}';
final backupFile = File(path);
await backupFile.delete();

View file

@ -1,6 +1,7 @@
import 'dart:convert';
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/core/flatpak.dart';
import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/balance_display_mode.dart';
@ -335,15 +336,13 @@ abstract class DashboardViewModelBase with Store {
bool hasExchangeAction;
@computed
bool get isEnabledBuyAction =>
!settingsStore.disableBuy && availableBuyProviders.isNotEmpty;
bool get isEnabledBuyAction => !settingsStore.disableBuy && availableBuyProviders.isNotEmpty;
@observable
bool hasBuyAction;
@computed
bool get isEnabledSellAction =>
!settingsStore.disableSell && availableSellProviders.isNotEmpty;
bool get isEnabledSellAction => !settingsStore.disableSell && availableSellProviders.isNotEmpty;
@observable
bool hasSellAction;
@ -467,8 +466,13 @@ abstract class DashboardViewModelBase with Store {
void setSyncAll(bool value) => settingsStore.currentSyncAll = value;
Future<List<String>> checkAffectedWallets() async {
if (SettingsStoreBase.walletPasswordDirectInput) {
return [];
}
// await load file
final vulnerableSeedsString = await rootBundle.loadString('assets/text/cakewallet_weak_bitcoin_seeds_hashed_sorted_version1.txt');
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);
@ -477,7 +481,8 @@ abstract class DashboardViewModelBase with Store {
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 path =
await pathForWallet(name: walletInfo.name, type: walletInfo.type, isFlatpak: isFlatpak);
final jsonSource = await read(path: path, password: password);
final data = json.decode(jsonSource) as Map;
final mnemonic = data['mnemonic'] as String;

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/core/flatpak.dart';
import 'package:cake_wallet/core/wallet_creation_service.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/store/settings_store.dart';
@ -66,8 +67,8 @@ abstract class WalletCreationVMBase with Store {
}
walletCreationService.checkIfExists(name);
final dirPath = await pathForWalletDir(name: name, type: type);
final path = await pathForWallet(name: name, type: type);
final dirPath = await pathForWalletDir(name: name, type: type, isFlatpak: isFlatpak);
final path = await pathForWallet(name: name, type: type, isFlatpak: isFlatpak);
final credentials = restoreWallet != null
? getCredentialsFromRestoredWallet(options, restoreWallet)
: getCredentials(options);

View file

@ -1,6 +1,7 @@
#!/bin/bash
CAKEWALLET="cakewallet"
CAKEWALLET_FLATPAK="cakewallet-flatpak"
DIR=`pwd`
if [ -z "$APP_LINUX_TYPE" ]; then
@ -14,6 +15,8 @@ CONFIG_ARGS=""
case $APP_LINUX_TYPE in
$CAKEWALLET)
CONFIG_ARGS="--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --excludeFlutterSecureStorage";;
$CAKEWALLET_FLATPAK)
CONFIG_ARGS="--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --excludeFlutterSecureStorage --flatpak";;
esac
cp -rf pubspec_description.yaml pubspec.yaml

View file

@ -0,0 +1,33 @@
#!/bin/fish
set APP_LINUX_NAME ""
set APP_LINUX_VERSION ""
set APP_LINUX_BUILD_VERSION ""
set CAKEWALLET "cakewallet"
set CAKEWALLET_FLATPAK "cakewallet-flatpak"
set TYPES $CAKEWALLET $CAKEWALLET_FLATPAK
set APP_LINUX_TYPE $argv[1]
if not contains $APP_LINUX_TYPE $TYPES
echo "Wrong app type."
exit 1
end
set CAKEWALLET_NAME "Cake Wallet"
set CAKEWALLET_VERSION "1.4.0"
set CAKEWALLET_BUILD_NUMBER 13
switch $APP_LINUX_TYPE
case $CAKEWALLET
case $CAKEWALLET_FLATPAK
set APP_LINUX_NAME $CAKEWALLET_NAME
set APP_LINUX_VERSION $CAKEWALLET_VERSION
set APP_LINUX_BUILD_NUMBER $CAKEWALLET_BUILD_NUMBER
end
set -x APP_LINUX_TYPE $APP_LINUX_TYPE
set -x APP_LINUX_NAME $APP_LINUX_NAME
set -x APP_LINUX_VERSION $APP_LINUX_VERSION
set -x APP_LINUX_BUILD_NUMBER $APP_LINUX_BUILD_NUMBER

View file

@ -5,25 +5,25 @@ APP_LINUX_VERSION=""
APP_LINUX_BUILD_VERSION=""
CAKEWALLET="cakewallet"
CAKEWALLET_FLATPAK="cakewallet-flatpak"
TYPES=($CAKEWALLET)
APP_LINUX_TYPE=$CAKEWALLET
TYPES=($CAKEWALLET $CAKEWALLET_FLATPAK)
APP_LINUX_TYPE=$1
if [ -n "$1" ]; then
APP_LINUX_TYPE=$1
if ! [[ " ${TYPES[*]} " =~ " ${APP_LINUX_TYPE} " ]]; then
echo ${TYPES[*]}
echo ${APP_LINUX_TYPE}
exit 1
fi
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="1.4.1"
CAKEWALLET_BUILD_NUMBER=14
if ! [[ " ${TYPES[*]} " =~ " ${APP_LINUX_TYPE} " ]]; then
echo "Wrong app type."
exit 1
fi
case $APP_LINUX_TYPE in
$CAKEWALLET)
$CAKEWALLET)
;;
$CAKEWALLET_FLATPAK)
APP_LINUX_NAME=$CAKEWALLET_NAME
APP_LINUX_VERSION=$CAKEWALLET_VERSION
APP_LINUX_BUILD_NUMBER=$CAKEWALLET_BUILD_NUMBER;;

View file

@ -9,6 +9,7 @@ const nanoOutputPath = 'lib/nano/nano.dart';
const polygonOutputPath = 'lib/polygon/polygon.dart';
const walletTypesPath = 'lib/wallet_types.g.dart';
const secureStoragePath = 'lib/core/secure_storage.dart';
const flatpakPath = 'lib/core/flatpak.dart';
const pubspecDefaultPath = 'pubspec_default.yaml';
const pubspecOutputPath = 'pubspec.yaml';
@ -24,6 +25,7 @@ Future<void> main(List<String> args) async {
final hasPolygon = args.contains('${prefix}polygon');
final excludeFlutterSecureStorage = args.contains('${prefix}excludeFlutterSecureStorage');
final isFlatpak = args.contains('${prefix}flatpak');
await generateBitcoin(hasBitcoin);
await generateMonero(hasMonero);
await generateHaven(hasHaven);
@ -55,6 +57,7 @@ Future<void> main(List<String> args) async {
hasPolygon: hasPolygon,
);
await injectSecureStorage(!excludeFlutterSecureStorage);
await injectFlatpak(isFlatpak);
}
Future<void> generateBitcoin(bool hasImplementation) async {
@ -132,8 +135,8 @@ abstract class Bitcoin {
List<Unspent> getUnspents(Object wallet);
void updateUnspents(Object wallet);
WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect);
WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect);
WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect, bool isFlatpak);
WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect, bool isFlatpak);
TransactionPriority getBitcoinTransactionPriorityMedium();
TransactionPriority getLitecoinTransactionPriorityMedium();
TransactionPriority getBitcoinTransactionPrioritySlow();
@ -296,7 +299,7 @@ abstract class Monero {
void setCurrentAccount(Object wallet, int id, String label, String? balance);
void onStartup();
int getTransactionInfoAccountId(TransactionInfo tx);
WalletService createMoneroWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
WalletService createMoneroWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isFlatpak);
Map<String, String> pendingTransactionInfo(Object transaction);
}
@ -547,7 +550,7 @@ import 'package:cw_ethereum/ethereum_transaction_priority.dart';
const ethereumContent = """
abstract class Ethereum {
List<String> getEthereumWordList(String language);
WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource, bool isDirect);
WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource, bool isDirect, bool isFlatpak);
WalletCredentials createEthereumNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password});
WalletCredentials createEthereumRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password});
WalletCredentials createEthereumRestoreWalletFromPrivateKey({required String name, required String privateKey, required String password});
@ -634,7 +637,7 @@ import 'package:cw_ethereum/ethereum_mnemonics.dart';
const polygonContent = """
abstract class Polygon {
List<String> getPolygonWordList(String language);
WalletService createPolygonWalletService(Box<WalletInfo> walletInfoSource, bool isDirect);
WalletService createPolygonWalletService(Box<WalletInfo> walletInfoSource, bool isDirec, bool isFlatpak);
WalletCredentials createPolygonNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password});
WalletCredentials createPolygonRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password});
WalletCredentials createPolygonRestoreWalletFromPrivateKey({required String name, required String privateKey, required String password});
@ -717,7 +720,7 @@ abstract class BitcoinCash {
String getCashAddrFormat(String address);
WalletService createBitcoinCashWalletService(
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect);
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect, bool isFlatpak);
WalletCredentials createBitcoinCashNewWalletCredentials(
{required String name, WalletInfo? walletInfo, String? password});
@ -796,7 +799,7 @@ abstract class Nano {
void setCurrentAccount(Object wallet, int id, String label, String? balance);
WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource, bool isDirect);
WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource, bool isDirec, bool isFlatpak);
WalletCredentials createNanoNewWalletCredentials({
required String name,
@ -1054,7 +1057,8 @@ Future<void> generateWalletTypes(
}
Future<void> injectSecureStorage(bool hasFlutterSecureStorage) async {
const flutterSecureStorageHeader = "import 'package:flutter_secure_storage/flutter_secure_storage.dart';";
const flutterSecureStorageHeader =
"import 'package:flutter_secure_storage/flutter_secure_storage.dart';";
const abstractSecureStorage = """
abstract class SecureStorage {
Future<String?> read({required String key});
@ -1105,8 +1109,8 @@ class FakeSecureStorage extends SecureStorage {
}""";
final outputFile = File(secureStoragePath);
final header = hasFlutterSecureStorage
? '${flutterSecureStorageHeader}\n\nfinal SecureStorage secureStorageShared = DefaultSecureStorage();\n'
: 'final SecureStorage secureStorageShared = FakeSecureStorage();\n';
? '${flutterSecureStorageHeader}\n\nfinal SecureStorage secureStorageShared = DefaultSecureStorage();\n'
: 'final SecureStorage secureStorageShared = FakeSecureStorage();\n';
var output = '';
if (outputFile.existsSync()) {
await outputFile.delete();
@ -1121,4 +1125,14 @@ class FakeSecureStorage extends SecureStorage {
}
await outputFile.writeAsString(output);
}
}
Future<void> injectFlatpak(bool isFlatpak) async {
final outputFile = File(flatpakPath);
if (outputFile.existsSync()) {
await outputFile.delete();
}
await outputFile
.writeAsString(isFlatpak ? "const isFlatpak = true;" : "const isFlatpak = false;");
}