mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 11:39:22 +00:00
feat: add flatpak build variable to use different default storage location to avoid needing filesystem=home permission
This commit is contained in:
parent
67a96807d1
commit
54be0f863c
44 changed files with 1014 additions and 702 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -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
|
||||
|
|
|
@ -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`
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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!));
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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');
|
||||
|
|
18
lib/di.dart
18
lib/di.dart
|
@ -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');
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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');
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
33
scripts/linux/app_env.fish
Normal file
33
scripts/linux/app_env.fish
Normal 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
|
|
@ -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;;
|
||||
|
|
|
@ -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;");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue