mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-11-16 17:27:37 +00:00
Merge branch 'main' of https://github.com/cake-tech/cake_wallet into mweb-bg-sync-2
This commit is contained in:
commit
85fb1384d5
63 changed files with 912 additions and 474 deletions
1
.github/workflows/pr_test_build_android.yml
vendored
1
.github/workflows/pr_test_build_android.yml
vendored
|
@ -224,6 +224,7 @@ jobs:
|
||||||
cd /opt/android/cake_wallet/build/app/outputs/flutter-apk
|
cd /opt/android/cake_wallet/build/app/outputs/flutter-apk
|
||||||
mkdir test-apk
|
mkdir test-apk
|
||||||
cp app-arm64-v8a-release.apk test-apk/${{env.BRANCH_NAME}}.apk
|
cp app-arm64-v8a-release.apk test-apk/${{env.BRANCH_NAME}}.apk
|
||||||
|
cp app-x86_64-release.apk test-apk/${{env.BRANCH_NAME}}_x86.apk
|
||||||
|
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: kittaakos/upload-artifact-as-is@v0
|
uses: kittaakos/upload-artifact-as-is@v0
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
# Cake Wallet
|
# Cake Wallet
|
||||||
|
|
||||||
Cake Wallet is an open source, non-custodial, and private multi-currency crypto wallet for Android, iOS, macOS, and Linux.
|
[Cake Wallet](https://cakewallet.com) is an open source, non-custodial, and private multi-currency crypto wallet for Android, iOS, macOS, and Linux.
|
||||||
|
|
||||||
Cake Wallet includes support for several cryptocurrencies, including:
|
Cake Wallet includes support for several cryptocurrencies, including:
|
||||||
* Monero (XMR)
|
* Monero (XMR)
|
||||||
|
@ -26,7 +26,7 @@ Cake Wallet includes support for several cryptocurrencies, including:
|
||||||
* Ethereum (ETH)
|
* Ethereum (ETH)
|
||||||
* Litecoin (LTC)
|
* Litecoin (LTC)
|
||||||
* Bitcoin Cash (BCH)
|
* Bitcoin Cash (BCH)
|
||||||
* Polygon (MATIC)
|
* Polygon (Pol)
|
||||||
* Solana (SOL)
|
* Solana (SOL)
|
||||||
* Nano (XNO)
|
* Nano (XNO)
|
||||||
* Haven (XHV)
|
* Haven (XHV)
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
<!-- required for API 18 - 30 -->
|
<!-- required for API 18 - 30 -->
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
|
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="30" />
|
||||||
|
|
||||||
<!-- required for API <= 29 -->
|
<!-- required for API <= 29 -->
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
useSSL: true
|
useSSL: true
|
||||||
-
|
-
|
||||||
uri: btc-electrum.cakewallet.com:50002
|
uri: btc-electrum.cakewallet.com:50002
|
||||||
|
useSSL: true
|
||||||
isDefault: true
|
isDefault: true
|
||||||
-
|
-
|
||||||
uri: electrs.cakewallet.com:50001
|
uri: electrs.cakewallet.com:50001
|
||||||
|
|
BIN
assets/images/hardware_wallet/ledger_flex.png
Normal file
BIN
assets/images/hardware_wallet/ledger_flex.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/images/hardware_wallet/ledger_nano_s.png
Normal file
BIN
assets/images/hardware_wallet/ledger_nano_s.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
BIN
assets/images/hardware_wallet/ledger_nano_x.png
Normal file
BIN
assets/images/hardware_wallet/ledger_nano_x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
BIN
assets/images/hardware_wallet/ledger_stax.png
Normal file
BIN
assets/images/hardware_wallet/ledger_stax.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
|
@ -3,4 +3,5 @@ Added wallet groups
|
||||||
Silent Payment enhancements for speed & reliability
|
Silent Payment enhancements for speed & reliability
|
||||||
Monero enhancements
|
Monero enhancements
|
||||||
Introducing StealthEx and LetxExchange
|
Introducing StealthEx and LetxExchange
|
||||||
Additional ERC20 tokens scam detection
|
Additional ERC20 tokens scam detection
|
||||||
|
Bug fixes
|
|
@ -15,7 +15,7 @@ These steps will help you configure and execute a build of CakeWallet from its s
|
||||||
|
|
||||||
### 1. Installing Package Dependencies
|
### 1. Installing Package Dependencies
|
||||||
|
|
||||||
CakeWallet requires some packages to be install on your build system. You may easily install them on your build system with the following command:
|
CakeWallet requires some packages to be installed on your build system. You may easily install them on your build system with the following command:
|
||||||
|
|
||||||
`$ sudo apt install build-essential cmake pkg-config git curl autoconf libtool`
|
`$ sudo apt install build-essential cmake pkg-config git curl autoconf libtool`
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ Path to executable file will be:
|
||||||
|
|
||||||
# Flatpak
|
# Flatpak
|
||||||
|
|
||||||
For package the built application into flatpak you need fistly to install `flatpak` and `flatpak-builder`:
|
For package the built application into flatpak you need firstly to install `flatpak` and `flatpak-builder`:
|
||||||
|
|
||||||
`$ sudo apt install flatpak flatpak-builder`
|
`$ sudo apt install flatpak flatpak-builder`
|
||||||
|
|
||||||
|
|
|
@ -5,30 +5,31 @@ import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
import 'package:cw_bitcoin/utils.dart';
|
import 'package:cw_bitcoin/utils.dart';
|
||||||
import 'package:cw_core/hardware/hardware_account_data.dart';
|
import 'package:cw_core/hardware/hardware_account_data.dart';
|
||||||
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
|
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
|
|
||||||
class BitcoinHardwareWalletService {
|
class BitcoinHardwareWalletService {
|
||||||
BitcoinHardwareWalletService(this.ledger, this.device);
|
BitcoinHardwareWalletService(this.ledgerConnection);
|
||||||
|
|
||||||
final Ledger ledger;
|
final LedgerConnection ledgerConnection;
|
||||||
final LedgerDevice device;
|
|
||||||
|
|
||||||
Future<List<HardwareAccountData>> getAvailableAccounts({int index = 0, int limit = 5}) async {
|
Future<List<HardwareAccountData>> getAvailableAccounts(
|
||||||
final bitcoinLedgerApp = BitcoinLedgerApp(ledger);
|
{int index = 0, int limit = 5}) async {
|
||||||
|
final bitcoinLedgerApp = BitcoinLedgerApp(ledgerConnection);
|
||||||
|
|
||||||
final masterFp = await bitcoinLedgerApp.getMasterFingerprint(device);
|
final masterFp = await bitcoinLedgerApp.getMasterFingerprint();
|
||||||
print(masterFp);
|
|
||||||
|
|
||||||
final accounts = <HardwareAccountData>[];
|
final accounts = <HardwareAccountData>[];
|
||||||
final indexRange = List.generate(limit, (i) => i + index);
|
final indexRange = List.generate(limit, (i) => i + index);
|
||||||
|
|
||||||
for (final i in indexRange) {
|
for (final i in indexRange) {
|
||||||
final derivationPath = "m/84'/0'/$i'";
|
final derivationPath = "m/84'/0'/$i'";
|
||||||
final xpub = await bitcoinLedgerApp.getXPubKey(device, derivationPath: derivationPath);
|
final xpub =
|
||||||
|
await bitcoinLedgerApp.getXPubKey(derivationPath: derivationPath);
|
||||||
Bip32Slip10Secp256k1 hd =
|
Bip32Slip10Secp256k1 hd =
|
||||||
Bip32Slip10Secp256k1.fromExtendedKey(xpub).childKey(Bip32KeyIndex(0));
|
Bip32Slip10Secp256k1.fromExtendedKey(xpub).childKey(Bip32KeyIndex(0));
|
||||||
|
|
||||||
final address = generateP2WPKHAddress(hd: hd, index: 0, network: BitcoinNetwork.mainnet);
|
final address = generateP2WPKHAddress(
|
||||||
|
hd: hd, index: 0, network: BitcoinNetwork.mainnet);
|
||||||
|
|
||||||
accounts.add(HardwareAccountData(
|
accounts.add(HardwareAccountData(
|
||||||
address: address,
|
address: address,
|
||||||
|
|
|
@ -5,13 +5,13 @@ import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||||
|
import 'package:cw_bitcoin/psbt_transaction_builder.dart';
|
||||||
import 'package:cw_core/encryption_file_utils.dart';
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_bitcoin/electrum_derivations.dart';
|
import 'package:cw_bitcoin/electrum_derivations.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
|
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
|
||||||
import 'package:cw_bitcoin/psbt_transaction_builder.dart';
|
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
@ -19,7 +19,7 @@ import 'package:cw_core/wallet_keys_file.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
|
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
part 'bitcoin_wallet.g.dart';
|
part 'bitcoin_wallet.g.dart';
|
||||||
|
@ -61,8 +61,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
encryptionFileUtils: encryptionFileUtils,
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
currency:
|
currency: networkParam == BitcoinNetwork.testnet
|
||||||
networkParam == BitcoinNetwork.testnet ? CryptoCurrency.tbtc : CryptoCurrency.btc,
|
? CryptoCurrency.tbtc
|
||||||
|
: CryptoCurrency.btc,
|
||||||
alwaysScan: alwaysScan,
|
alwaysScan: alwaysScan,
|
||||||
) {
|
) {
|
||||||
// in a standard BIP44 wallet, mainHd derivation path = m/84'/0'/0'/0 (account 0, index unspecified here)
|
// in a standard BIP44 wallet, mainHd derivation path = m/84'/0'/0'/0 (account 0, index unspecified here)
|
||||||
|
@ -80,11 +81,14 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
mainHd: hd,
|
mainHd: hd,
|
||||||
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
|
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
|
||||||
network: networkParam ?? network,
|
network: networkParam ?? network,
|
||||||
masterHd: seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
|
masterHd:
|
||||||
|
seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
|
||||||
|
isHardwareWallet: walletInfo.isHardwareWallet,
|
||||||
);
|
);
|
||||||
|
|
||||||
autorun((_) {
|
autorun((_) {
|
||||||
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
|
this.walletAddresses.isEnabledAutoGenerateSubaddress =
|
||||||
|
this.isEnabledAutoGenerateSubaddress;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,8 +189,10 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
walletInfo.derivationInfo ??= DerivationInfo();
|
walletInfo.derivationInfo ??= DerivationInfo();
|
||||||
|
|
||||||
// set the default if not present:
|
// set the default if not present:
|
||||||
walletInfo.derivationInfo!.derivationPath ??= snp?.derivationPath ?? electrum_path;
|
walletInfo.derivationInfo!.derivationPath ??=
|
||||||
walletInfo.derivationInfo!.derivationType ??= snp?.derivationType ?? DerivationType.electrum;
|
snp?.derivationPath ?? electrum_path;
|
||||||
|
walletInfo.derivationInfo!.derivationType ??=
|
||||||
|
snp?.derivationType ?? DerivationType.electrum;
|
||||||
|
|
||||||
Uint8List? seedBytes = null;
|
Uint8List? seedBytes = null;
|
||||||
final mnemonic = keysData.mnemonic;
|
final mnemonic = keysData.mnemonic;
|
||||||
|
@ -228,15 +234,14 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ledger? _ledger;
|
LedgerConnection? _ledgerConnection;
|
||||||
LedgerDevice? _ledgerDevice;
|
|
||||||
BitcoinLedgerApp? _bitcoinLedgerApp;
|
BitcoinLedgerApp? _bitcoinLedgerApp;
|
||||||
|
|
||||||
void setLedger(Ledger setLedger, LedgerDevice setLedgerDevice) {
|
@override
|
||||||
_ledger = setLedger;
|
void setLedgerConnection(LedgerConnection connection) {
|
||||||
_ledgerDevice = setLedgerDevice;
|
_ledgerConnection = connection;
|
||||||
_bitcoinLedgerApp =
|
_bitcoinLedgerApp = BitcoinLedgerApp(_ledgerConnection!,
|
||||||
BitcoinLedgerApp(_ledger!, derivationPath: walletInfo.derivationInfo!.derivationPath!);
|
derivationPath: walletInfo.derivationInfo!.derivationPath!);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -251,12 +256,14 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
BitcoinOrdering inputOrdering = BitcoinOrdering.bip69,
|
BitcoinOrdering inputOrdering = BitcoinOrdering.bip69,
|
||||||
BitcoinOrdering outputOrdering = BitcoinOrdering.bip69,
|
BitcoinOrdering outputOrdering = BitcoinOrdering.bip69,
|
||||||
}) async {
|
}) async {
|
||||||
final masterFingerprint = await _bitcoinLedgerApp!.getMasterFingerprint(_ledgerDevice!);
|
final masterFingerprint = await _bitcoinLedgerApp!.getMasterFingerprint();
|
||||||
|
|
||||||
final psbtReadyInputs = <PSBTReadyUtxoWithAddress>[];
|
final psbtReadyInputs = <PSBTReadyUtxoWithAddress>[];
|
||||||
for (final utxo in utxos) {
|
for (final utxo in utxos) {
|
||||||
final rawTx = await electrumClient.getTransactionHex(hash: utxo.utxo.txHash);
|
final rawTx =
|
||||||
final publicKeyAndDerivationPath = publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
|
await electrumClient.getTransactionHex(hash: utxo.utxo.txHash);
|
||||||
|
final publicKeyAndDerivationPath =
|
||||||
|
publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
|
||||||
|
|
||||||
psbtReadyInputs.add(PSBTReadyUtxoWithAddress(
|
psbtReadyInputs.add(PSBTReadyUtxoWithAddress(
|
||||||
utxo: utxo.utxo,
|
utxo: utxo.utxo,
|
||||||
|
@ -268,10 +275,10 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
final psbt =
|
final psbt = PSBTTransactionBuild(
|
||||||
PSBTTransactionBuild(inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF);
|
inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF);
|
||||||
|
|
||||||
final rawHex = await _bitcoinLedgerApp!.signPsbt(_ledgerDevice!, psbt: psbt.psbt);
|
final rawHex = await _bitcoinLedgerApp!.signPsbt(psbt: psbt.psbt);
|
||||||
return BtcTransaction.fromRaw(BytesUtils.toHexString(rawHex));
|
return BtcTransaction.fromRaw(BytesUtils.toHexString(rawHex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,14 +286,16 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
Future<String> signMessage(String message, {String? address = null}) async {
|
Future<String> signMessage(String message, {String? address = null}) async {
|
||||||
if (walletInfo.isHardwareWallet) {
|
if (walletInfo.isHardwareWallet) {
|
||||||
final addressEntry = address != null
|
final addressEntry = address != null
|
||||||
? walletAddresses.allAddresses.firstWhere((element) => element.address == address)
|
? walletAddresses.allAddresses
|
||||||
|
.firstWhere((element) => element.address == address)
|
||||||
: null;
|
: null;
|
||||||
final index = addressEntry?.index ?? 0;
|
final index = addressEntry?.index ?? 0;
|
||||||
final isChange = addressEntry?.isHidden == true ? 1 : 0;
|
final isChange = addressEntry?.isHidden == true ? 1 : 0;
|
||||||
final accountPath = walletInfo.derivationInfo?.derivationPath;
|
final accountPath = walletInfo.derivationInfo?.derivationPath;
|
||||||
final derivationPath = accountPath != null ? "$accountPath/$isChange/$index" : null;
|
final derivationPath =
|
||||||
|
accountPath != null ? "$accountPath/$isChange/$index" : null;
|
||||||
|
|
||||||
final signature = await _bitcoinLedgerApp!.signMessage(_ledgerDevice!,
|
final signature = await _bitcoinLedgerApp!.signMessage(
|
||||||
message: ascii.encode(message), signDerivationPath: derivationPath);
|
message: ascii.encode(message), signDerivationPath: derivationPath);
|
||||||
return base64Encode(signature);
|
return base64Encode(signature);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
||||||
required super.mainHd,
|
required super.mainHd,
|
||||||
required super.sideHd,
|
required super.sideHd,
|
||||||
required super.network,
|
required super.network,
|
||||||
|
required super.isHardwareWallet,
|
||||||
super.initialAddresses,
|
super.initialAddresses,
|
||||||
super.initialRegularAddressIndex,
|
super.initialRegularAddressIndex,
|
||||||
super.initialChangeAddressIndex,
|
super.initialChangeAddressIndex,
|
||||||
|
|
|
@ -6,7 +6,6 @@ import 'dart:isolate';
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_wallet.dart';
|
import 'package:cw_bitcoin/bitcoin_wallet.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:cw_core/encryption_file_utils.dart';
|
|
||||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:cw_bitcoin/address_from_output.dart';
|
import 'package:cw_bitcoin/address_from_output.dart';
|
||||||
|
@ -26,6 +25,8 @@ import 'package:cw_bitcoin/exceptions.dart';
|
||||||
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
|
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
|
||||||
import 'package:cw_bitcoin/utils.dart';
|
import 'package:cw_bitcoin/utils.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
|
import 'package:cw_core/get_height_by_date.dart';
|
||||||
import 'package:cw_core/node.dart';
|
import 'package:cw_core/node.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/pending_transaction.dart';
|
import 'package:cw_core/pending_transaction.dart';
|
||||||
|
@ -37,10 +38,10 @@ import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_keys_file.dart';
|
import 'package:cw_core/wallet_keys_file.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:cw_core/get_height_by_date.dart';
|
|
||||||
import 'package:cw_core/unspent_coin_type.dart';
|
import 'package:cw_core/unspent_coin_type.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as ledger;
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:rxdart/subjects.dart';
|
import 'package:rxdart/subjects.dart';
|
||||||
import 'package:sp_scanner/sp_scanner.dart';
|
import 'package:sp_scanner/sp_scanner.dart';
|
||||||
|
@ -51,9 +52,10 @@ part 'electrum_wallet.g.dart';
|
||||||
|
|
||||||
class ElectrumWallet = ElectrumWalletBase with _$ElectrumWallet;
|
class ElectrumWallet = ElectrumWalletBase with _$ElectrumWallet;
|
||||||
|
|
||||||
abstract class ElectrumWalletBase
|
abstract class ElectrumWalletBase extends WalletBase<
|
||||||
extends WalletBase<ElectrumBalance, ElectrumTransactionHistory, ElectrumTransactionInfo>
|
ElectrumBalance,
|
||||||
with Store, WalletKeysFile {
|
ElectrumTransactionHistory,
|
||||||
|
ElectrumTransactionInfo> with Store, WalletKeysFile {
|
||||||
ElectrumWalletBase({
|
ElectrumWalletBase({
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
|
@ -69,8 +71,8 @@ abstract class ElectrumWalletBase
|
||||||
ElectrumBalance? initialBalance,
|
ElectrumBalance? initialBalance,
|
||||||
CryptoCurrency? currency,
|
CryptoCurrency? currency,
|
||||||
this.alwaysScan,
|
this.alwaysScan,
|
||||||
}) : accountHD =
|
}) : accountHD = getAccountHDWallet(
|
||||||
getAccountHDWallet(currency, network, seedBytes, xpub, walletInfo.derivationInfo),
|
currency, network, seedBytes, xpub, walletInfo.derivationInfo),
|
||||||
syncStatus = NotConnectedSyncStatus(),
|
syncStatus = NotConnectedSyncStatus(),
|
||||||
_password = password,
|
_password = password,
|
||||||
_feeRates = <int>[],
|
_feeRates = <int>[],
|
||||||
|
@ -105,8 +107,12 @@ abstract class ElectrumWalletBase
|
||||||
sharedPrefs.complete(SharedPreferences.getInstance());
|
sharedPrefs.complete(SharedPreferences.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bip32Slip10Secp256k1 getAccountHDWallet(CryptoCurrency? currency, BasedUtxoNetwork network,
|
static Bip32Slip10Secp256k1 getAccountHDWallet(
|
||||||
Uint8List? seedBytes, String? xpub, DerivationInfo? derivationInfo) {
|
CryptoCurrency? currency,
|
||||||
|
BasedUtxoNetwork network,
|
||||||
|
Uint8List? seedBytes,
|
||||||
|
String? xpub,
|
||||||
|
DerivationInfo? derivationInfo) {
|
||||||
if (seedBytes == null && xpub == null) {
|
if (seedBytes == null && xpub == null) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"To create a Wallet you need either a seed or an xpub. This should not happen");
|
"To create a Wallet you need either a seed or an xpub. This should not happen");
|
||||||
|
@ -117,8 +123,9 @@ abstract class ElectrumWalletBase
|
||||||
case CryptoCurrency.btc:
|
case CryptoCurrency.btc:
|
||||||
case CryptoCurrency.ltc:
|
case CryptoCurrency.ltc:
|
||||||
case CryptoCurrency.tbtc:
|
case CryptoCurrency.tbtc:
|
||||||
return Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath(
|
return Bip32Slip10Secp256k1.fromSeed(seedBytes, getKeyNetVersion(network))
|
||||||
_hardenedDerivationPath(derivationInfo?.derivationPath ?? electrum_path))
|
.derivePath(_hardenedDerivationPath(
|
||||||
|
derivationInfo?.derivationPath ?? electrum_path))
|
||||||
as Bip32Slip10Secp256k1;
|
as Bip32Slip10Secp256k1;
|
||||||
case CryptoCurrency.bch:
|
case CryptoCurrency.bch:
|
||||||
return bitcoinCashHDWallet(seedBytes);
|
return bitcoinCashHDWallet(seedBytes);
|
||||||
|
@ -127,15 +134,26 @@ abstract class ElectrumWalletBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Bip32Slip10Secp256k1.fromExtendedKey(xpub!);
|
return Bip32Slip10Secp256k1.fromExtendedKey(
|
||||||
|
xpub!, getKeyNetVersion(network));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bip32Slip10Secp256k1 bitcoinCashHDWallet(Uint8List seedBytes) =>
|
static Bip32Slip10Secp256k1 bitcoinCashHDWallet(Uint8List seedBytes) =>
|
||||||
Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath("m/44'/145'/0'") as Bip32Slip10Secp256k1;
|
Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath("m/44'/145'/0'")
|
||||||
|
as Bip32Slip10Secp256k1;
|
||||||
|
|
||||||
static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
|
static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
|
||||||
inputsCount * 68 + outputsCounts * 34 + 10;
|
inputsCount * 68 + outputsCounts * 34 + 10;
|
||||||
|
|
||||||
|
static Bip32KeyNetVersions? getKeyNetVersion(BasedUtxoNetwork network) {
|
||||||
|
switch (network) {
|
||||||
|
case LitecoinNetwork.mainnet:
|
||||||
|
return Bip44Conf.litecoinMainNet.altKeyNetVer;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool? alwaysScan;
|
bool? alwaysScan;
|
||||||
|
|
||||||
final Bip32Slip10Secp256k1 accountHD;
|
final Bip32Slip10Secp256k1 accountHD;
|
||||||
|
@ -657,8 +675,9 @@ abstract class ElectrumWalletBase
|
||||||
ECPrivate? privkey;
|
ECPrivate? privkey;
|
||||||
bool? isSilentPayment = false;
|
bool? isSilentPayment = false;
|
||||||
|
|
||||||
final hd =
|
final hd = utx.bitcoinAddressRecord.isHidden
|
||||||
utx.bitcoinAddressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd;
|
? walletAddresses.sideHd
|
||||||
|
: walletAddresses.mainHd;
|
||||||
|
|
||||||
if (utx.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) {
|
if (utx.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) {
|
||||||
final unspentAddress = utx.bitcoinAddressRecord as BitcoinSilentPaymentAddressRecord;
|
final unspentAddress = utx.bitcoinAddressRecord as BitcoinSilentPaymentAddressRecord;
|
||||||
|
@ -856,7 +875,7 @@ abstract class ElectrumWalletBase
|
||||||
inputs: utxoDetails.availableInputs,
|
inputs: utxoDetails.availableInputs,
|
||||||
outputs: updatedOutputs,
|
outputs: updatedOutputs,
|
||||||
);
|
);
|
||||||
final address = RegexUtils.addressTypeFromStr(changeAddress, network);
|
final address = RegexUtils.addressTypeFromStr(changeAddress.address, network);
|
||||||
updatedOutputs.add(BitcoinOutput(
|
updatedOutputs.add(BitcoinOutput(
|
||||||
address: address,
|
address: address,
|
||||||
value: BigInt.from(amountLeftForChangeAndFee),
|
value: BigInt.from(amountLeftForChangeAndFee),
|
||||||
|
@ -868,6 +887,14 @@ abstract class ElectrumWalletBase
|
||||||
isChange: true,
|
isChange: true,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// Get Derivation path for change Address since it is needed in Litecoin and BitcoinCash hardware Wallets
|
||||||
|
final changeDerivationPath =
|
||||||
|
"${_hardenedDerivationPath(walletInfo.derivationInfo?.derivationPath ?? "m/0'")}"
|
||||||
|
"/${changeAddress.isHidden ? "1" : "0"}"
|
||||||
|
"/${changeAddress.index}";
|
||||||
|
utxoDetails.publicKeys[address.pubKeyHash()] =
|
||||||
|
PublicKeyWithDerivationPath('', changeDerivationPath);
|
||||||
|
|
||||||
// calcFee updates the silent payment outputs to calculate the tx size accounting
|
// calcFee updates the silent payment outputs to calculate the tx size accounting
|
||||||
// for taproot addresses, but if more inputs are needed to make up for fees,
|
// for taproot addresses, but if more inputs are needed to make up for fees,
|
||||||
// the silent payment outputs need to be recalculated for the new inputs
|
// the silent payment outputs need to be recalculated for the new inputs
|
||||||
|
@ -1086,7 +1113,7 @@ abstract class ElectrumWalletBase
|
||||||
|
|
||||||
if (sendAll) {
|
if (sendAll) {
|
||||||
estimatedTx = await estimateSendAllTx(
|
estimatedTx = await estimateSendAllTx(
|
||||||
outputs,
|
updatedOutputs,
|
||||||
feeRateInt,
|
feeRateInt,
|
||||||
memo: memo,
|
memo: memo,
|
||||||
credentialsAmount: credentialsAmount,
|
credentialsAmount: credentialsAmount,
|
||||||
|
@ -1138,7 +1165,7 @@ abstract class ElectrumWalletBase
|
||||||
if (network is BitcoinCashNetwork) {
|
if (network is BitcoinCashNetwork) {
|
||||||
txb = ForkedTransactionBuilder(
|
txb = ForkedTransactionBuilder(
|
||||||
utxos: estimatedTx.utxos,
|
utxos: estimatedTx.utxos,
|
||||||
outputs: outputs,
|
outputs: updatedOutputs,
|
||||||
fee: BigInt.from(estimatedTx.fee),
|
fee: BigInt.from(estimatedTx.fee),
|
||||||
network: network,
|
network: network,
|
||||||
memo: estimatedTx.memo,
|
memo: estimatedTx.memo,
|
||||||
|
@ -1229,6 +1256,9 @@ abstract class ElectrumWalletBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setLedgerConnection(ledger.LedgerConnection connection) =>
|
||||||
|
throw UnimplementedError();
|
||||||
|
|
||||||
Future<BtcTransaction> buildHardwareWalletTransaction({
|
Future<BtcTransaction> buildHardwareWalletTransaction({
|
||||||
required List<BitcoinBaseOutput> outputs,
|
required List<BitcoinBaseOutput> outputs,
|
||||||
required BigInt fee,
|
required BigInt fee,
|
||||||
|
@ -1586,7 +1616,9 @@ abstract class ElectrumWalletBase
|
||||||
|
|
||||||
final btcAddress = RegexUtils.addressTypeFromStr(addressRecord.address, network);
|
final btcAddress = RegexUtils.addressTypeFromStr(addressRecord.address, network);
|
||||||
final privkey = generateECPrivate(
|
final privkey = generateECPrivate(
|
||||||
hd: addressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd,
|
hd: addressRecord.isHidden
|
||||||
|
? walletAddresses.sideHd
|
||||||
|
: walletAddresses.mainHd,
|
||||||
index: addressRecord.index,
|
index: addressRecord.index,
|
||||||
network: network);
|
network: network);
|
||||||
|
|
||||||
|
@ -1768,7 +1800,8 @@ abstract class ElectrumWalletBase
|
||||||
|
|
||||||
if (height != null) {
|
if (height != null) {
|
||||||
if (time == null && height > 0) {
|
if (time == null && height > 0) {
|
||||||
time = (getDateByBitcoinHeight(height).millisecondsSinceEpoch / 1000).round();
|
time = (getDateByBitcoinHeight(height).millisecondsSinceEpoch / 1000)
|
||||||
|
.round();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (confirmations == null) {
|
if (confirmations == null) {
|
||||||
|
|
|
@ -36,6 +36,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
required this.mainHd,
|
required this.mainHd,
|
||||||
required this.sideHd,
|
required this.sideHd,
|
||||||
required this.network,
|
required this.network,
|
||||||
|
required this.isHardwareWallet,
|
||||||
List<BitcoinAddressRecord>? initialAddresses,
|
List<BitcoinAddressRecord>? initialAddresses,
|
||||||
Map<String, int>? initialRegularAddressIndex,
|
Map<String, int>? initialRegularAddressIndex,
|
||||||
Map<String, int>? initialChangeAddressIndex,
|
Map<String, int>? initialChangeAddressIndex,
|
||||||
|
@ -44,6 +45,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
List<BitcoinAddressRecord>? initialMwebAddresses,
|
List<BitcoinAddressRecord>? initialMwebAddresses,
|
||||||
Bip32Slip10Secp256k1? masterHd,
|
Bip32Slip10Secp256k1? masterHd,
|
||||||
BitcoinAddressType? initialAddressPageType,
|
BitcoinAddressType? initialAddressPageType,
|
||||||
|
|
||||||
}) : _addresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? []).toSet()),
|
}) : _addresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? []).toSet()),
|
||||||
addressesByReceiveType =
|
addressesByReceiveType =
|
||||||
ObservableList<BaseBitcoinAddressRecord>.of((<BitcoinAddressRecord>[]).toSet()),
|
ObservableList<BaseBitcoinAddressRecord>.of((<BitcoinAddressRecord>[]).toSet()),
|
||||||
|
@ -112,6 +114,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
final BasedUtxoNetwork network;
|
final BasedUtxoNetwork network;
|
||||||
final Bip32Slip10Secp256k1 mainHd;
|
final Bip32Slip10Secp256k1 mainHd;
|
||||||
final Bip32Slip10Secp256k1 sideHd;
|
final Bip32Slip10Secp256k1 sideHd;
|
||||||
|
final bool isHardwareWallet;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
SilentPaymentOwner? silentAddress;
|
SilentPaymentOwner? silentAddress;
|
||||||
|
@ -240,15 +243,17 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
await _generateInitialAddresses(type: P2pkhAddressType.p2pkh);
|
await _generateInitialAddresses(type: P2pkhAddressType.p2pkh);
|
||||||
} else if (walletInfo.type == WalletType.litecoin) {
|
} else if (walletInfo.type == WalletType.litecoin) {
|
||||||
await _generateInitialAddresses(type: SegwitAddresType.p2wpkh);
|
await _generateInitialAddresses(type: SegwitAddresType.p2wpkh);
|
||||||
if (Platform.isAndroid || Platform.isIOS) {
|
if ((Platform.isAndroid || Platform.isIOS) && !isHardwareWallet) {
|
||||||
await _generateInitialAddresses(type: SegwitAddresType.mweb);
|
await _generateInitialAddresses(type: SegwitAddresType.mweb);
|
||||||
}
|
}
|
||||||
} else if (walletInfo.type == WalletType.bitcoin) {
|
} else if (walletInfo.type == WalletType.bitcoin) {
|
||||||
await _generateInitialAddresses();
|
await _generateInitialAddresses();
|
||||||
await _generateInitialAddresses(type: P2pkhAddressType.p2pkh);
|
if (!isHardwareWallet) {
|
||||||
await _generateInitialAddresses(type: P2shAddressType.p2wpkhInP2sh);
|
await _generateInitialAddresses(type: P2pkhAddressType.p2pkh);
|
||||||
await _generateInitialAddresses(type: SegwitAddresType.p2tr);
|
await _generateInitialAddresses(type: P2shAddressType.p2wpkhInP2sh);
|
||||||
await _generateInitialAddresses(type: SegwitAddresType.p2wsh);
|
await _generateInitialAddresses(type: SegwitAddresType.p2tr);
|
||||||
|
await _generateInitialAddresses(type: SegwitAddresType.p2wsh);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAddressesByMatch();
|
updateAddressesByMatch();
|
||||||
|
@ -267,7 +272,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<String> getChangeAddress({List<BitcoinUnspent>? inputs, List<BitcoinOutput>? outputs, bool isPegIn = false}) async {
|
Future<BitcoinAddressRecord> getChangeAddress({List<BitcoinUnspent>? inputs, List<BitcoinOutput>? outputs, bool isPegIn = false}) async {
|
||||||
updateChangeAddresses();
|
updateChangeAddresses();
|
||||||
|
|
||||||
if (changeAddresses.isEmpty) {
|
if (changeAddresses.isEmpty) {
|
||||||
|
@ -282,7 +287,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateChangeAddresses();
|
updateChangeAddresses();
|
||||||
final address = changeAddresses[currentChangeAddressIndex].address;
|
final address = changeAddresses[currentChangeAddressIndex];
|
||||||
currentChangeAddressIndex += 1;
|
currentChangeAddressIndex += 1;
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
@ -326,7 +331,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
);
|
);
|
||||||
|
|
||||||
silentAddresses.add(address);
|
silentAddresses.add(address);
|
||||||
updateAddressesByMatch();
|
Future.delayed(Duration.zero, () => updateAddressesByMatch());
|
||||||
|
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
@ -343,7 +348,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
network: network,
|
network: network,
|
||||||
);
|
);
|
||||||
_addresses.add(address);
|
_addresses.add(address);
|
||||||
updateAddressesByMatch();
|
Future.delayed(Duration.zero, () => updateAddressesByMatch());
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -670,7 +675,9 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
Bip32Slip10Secp256k1 _getHd(bool isHidden) => isHidden ? sideHd : mainHd;
|
Bip32Slip10Secp256k1 _getHd(bool isHidden) => isHidden ? sideHd : mainHd;
|
||||||
|
|
||||||
bool _isAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) => addr.type == type;
|
bool _isAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) => addr.type == type;
|
||||||
|
|
||||||
bool _isUnusedReceiveAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) =>
|
bool _isUnusedReceiveAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) =>
|
||||||
!addr.isHidden && !addr.isUsed && addr.type == type;
|
!addr.isHidden && !addr.isUsed && addr.type == type;
|
||||||
|
|
||||||
|
|
46
cw_bitcoin/lib/litecoin_hardware_wallet_service.dart
Normal file
46
cw_bitcoin/lib/litecoin_hardware_wallet_service.dart
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
|
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
|
import 'package:cw_bitcoin/utils.dart';
|
||||||
|
import 'package:cw_core/hardware/hardware_account_data.dart';
|
||||||
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
|
import 'package:ledger_litecoin/ledger_litecoin.dart';
|
||||||
|
|
||||||
|
class LitecoinHardwareWalletService {
|
||||||
|
LitecoinHardwareWalletService(this.ledgerConnection);
|
||||||
|
|
||||||
|
final LedgerConnection ledgerConnection;
|
||||||
|
|
||||||
|
Future<List<HardwareAccountData>> getAvailableAccounts(
|
||||||
|
{int index = 0, int limit = 5}) async {
|
||||||
|
final litecoinLedgerApp = LitecoinLedgerApp(ledgerConnection);
|
||||||
|
|
||||||
|
await litecoinLedgerApp.getVersion();
|
||||||
|
|
||||||
|
final accounts = <HardwareAccountData>[];
|
||||||
|
final indexRange = List.generate(limit, (i) => i + index);
|
||||||
|
final xpubVersion = Bip44Conf.litecoinMainNet.altKeyNetVer;
|
||||||
|
|
||||||
|
for (final i in indexRange) {
|
||||||
|
final derivationPath = "m/84'/2'/$i'";
|
||||||
|
final xpub = await litecoinLedgerApp.getXPubKey(
|
||||||
|
accountsDerivationPath: derivationPath,
|
||||||
|
xPubVersion: int.parse(hex.encode(xpubVersion.public), radix: 16));
|
||||||
|
final hd = Bip32Slip10Secp256k1.fromExtendedKey(xpub, xpubVersion)
|
||||||
|
.childKey(Bip32KeyIndex(0));
|
||||||
|
|
||||||
|
final address = generateP2WPKHAddress(
|
||||||
|
hd: hd, index: 0, network: LitecoinNetwork.mainnet);
|
||||||
|
|
||||||
|
accounts.add(HardwareAccountData(
|
||||||
|
address: address,
|
||||||
|
accountIndex: i,
|
||||||
|
derivationPath: derivationPath,
|
||||||
|
xpub: xpub,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return accounts;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:convert/convert.dart' as convert;
|
import 'package:convert/convert.dart' as convert;
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
@ -37,6 +39,8 @@ import 'package:cw_core/wallet_keys_file.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:grpc/grpc.dart';
|
import 'package:grpc/grpc.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
|
import 'package:ledger_litecoin/ledger_litecoin.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:cw_mweb/cw_mweb.dart';
|
import 'package:cw_mweb/cw_mweb.dart';
|
||||||
|
@ -50,12 +54,13 @@ class LitecoinWallet = LitecoinWalletBase with _$LitecoinWallet;
|
||||||
|
|
||||||
abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
LitecoinWalletBase({
|
LitecoinWalletBase({
|
||||||
required String mnemonic,
|
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
required Uint8List seedBytes,
|
|
||||||
required EncryptionFileUtils encryptionFileUtils,
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
|
Uint8List? seedBytes,
|
||||||
|
String? mnemonic,
|
||||||
|
String? xpub,
|
||||||
String? passphrase,
|
String? passphrase,
|
||||||
String? addressPageType,
|
String? addressPageType,
|
||||||
List<BitcoinAddressRecord>? initialAddresses,
|
List<BitcoinAddressRecord>? initialAddresses,
|
||||||
|
@ -68,6 +73,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
}) : super(
|
}) : super(
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
password: password,
|
password: password,
|
||||||
|
xpub: xpub,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
network: LitecoinNetwork.mainnet,
|
network: LitecoinNetwork.mainnet,
|
||||||
|
@ -78,8 +84,14 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
currency: CryptoCurrency.ltc,
|
currency: CryptoCurrency.ltc,
|
||||||
alwaysScan: alwaysScan,
|
alwaysScan: alwaysScan,
|
||||||
) {
|
) {
|
||||||
mwebHd = Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath("m/1000'") as Bip32Slip10Secp256k1;
|
if (seedBytes != null) {
|
||||||
mwebEnabled = alwaysScan ?? false;
|
mwebHd = Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath(
|
||||||
|
"m/1000'") as Bip32Slip10Secp256k1;
|
||||||
|
mwebEnabled = alwaysScan ?? false;
|
||||||
|
} else {
|
||||||
|
mwebHd = null;
|
||||||
|
mwebEnabled = false;
|
||||||
|
}
|
||||||
walletAddresses = LitecoinWalletAddresses(
|
walletAddresses = LitecoinWalletAddresses(
|
||||||
walletInfo,
|
walletInfo,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
|
@ -91,6 +103,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
network: network,
|
network: network,
|
||||||
mwebHd: mwebHd,
|
mwebHd: mwebHd,
|
||||||
mwebEnabled: mwebEnabled,
|
mwebEnabled: mwebEnabled,
|
||||||
|
isHardwareWallet: walletInfo.isHardwareWallet,
|
||||||
);
|
);
|
||||||
autorun((_) {
|
autorun((_) {
|
||||||
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
|
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
|
||||||
|
@ -126,7 +139,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
late final Bip32Slip10Secp256k1 mwebHd;
|
late final Bip32Slip10Secp256k1? mwebHd;
|
||||||
late final Box<MwebUtxo> mwebUtxosBox;
|
late final Box<MwebUtxo> mwebUtxosBox;
|
||||||
Timer? _syncTimer;
|
Timer? _syncTimer;
|
||||||
Timer? _feeRatesTimer;
|
Timer? _feeRatesTimer;
|
||||||
|
@ -138,8 +151,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
@observable
|
@observable
|
||||||
SyncStatus mwebSyncStatus = NotConnectedSyncStatus();
|
SyncStatus mwebSyncStatus = NotConnectedSyncStatus();
|
||||||
|
|
||||||
List<int> get scanSecret => mwebHd.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw;
|
List<int> get scanSecret => mwebHd!.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw;
|
||||||
List<int> get spendSecret => mwebHd.childKey(Bip32KeyIndex(0x80000001)).privateKey.privKey.raw;
|
List<int> get spendSecret => mwebHd!.childKey(Bip32KeyIndex(0x80000001)).privateKey.privKey.raw;
|
||||||
|
|
||||||
static Future<LitecoinWallet> create(
|
static Future<LitecoinWallet> create(
|
||||||
{required String mnemonic,
|
{required String mnemonic,
|
||||||
|
@ -249,14 +262,15 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
return LitecoinWallet(
|
return LitecoinWallet(
|
||||||
mnemonic: keysData.mnemonic!,
|
mnemonic: keysData.mnemonic,
|
||||||
|
xpub: keysData.xPub,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
initialAddresses: snp?.addresses,
|
initialAddresses: snp?.addresses,
|
||||||
initialMwebAddresses: snp?.mwebAddresses,
|
initialMwebAddresses: snp?.mwebAddresses,
|
||||||
initialBalance: snp?.balance,
|
initialBalance: snp?.balance,
|
||||||
seedBytes: seedBytes!,
|
seedBytes: seedBytes,
|
||||||
passphrase: passphrase,
|
passphrase: passphrase,
|
||||||
encryptionFileUtils: encryptionFileUtils,
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
initialRegularAddressIndex: snp?.regularAddressIndex,
|
initialRegularAddressIndex: snp?.regularAddressIndex,
|
||||||
|
@ -935,7 +949,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
|
|
||||||
if (!mwebEnabled) {
|
if (!mwebEnabled) {
|
||||||
tx.changeAddressOverride =
|
tx.changeAddressOverride =
|
||||||
await (walletAddresses as LitecoinWalletAddresses).getChangeAddress(isPegIn: false);
|
(await (walletAddresses as LitecoinWalletAddresses)
|
||||||
|
.getChangeAddress(isPegIn: false))
|
||||||
|
.address;
|
||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
await waitForMwebAddresses();
|
await waitForMwebAddresses();
|
||||||
|
@ -974,8 +990,10 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
|
|
||||||
bool isPegIn = !hasMwebInput && hasMwebOutput;
|
bool isPegIn = !hasMwebInput && hasMwebOutput;
|
||||||
bool isRegular = !hasMwebInput && !hasMwebOutput;
|
bool isRegular = !hasMwebInput && !hasMwebOutput;
|
||||||
tx.changeAddressOverride = await (walletAddresses as LitecoinWalletAddresses)
|
tx.changeAddressOverride =
|
||||||
.getChangeAddress(isPegIn: isPegIn || isRegular);
|
(await (walletAddresses as LitecoinWalletAddresses)
|
||||||
|
.getChangeAddress(isPegIn: isPegIn || isRegular))
|
||||||
|
.address;
|
||||||
if (!hasMwebInput && !hasMwebOutput) {
|
if (!hasMwebInput && !hasMwebOutput) {
|
||||||
tx.isMweb = false;
|
tx.isMweb = false;
|
||||||
return tx;
|
return tx;
|
||||||
|
@ -1215,4 +1233,64 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LedgerConnection? _ledgerConnection;
|
||||||
|
LitecoinLedgerApp? _litecoinLedgerApp;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setLedgerConnection(LedgerConnection connection) {
|
||||||
|
_ledgerConnection = connection;
|
||||||
|
_litecoinLedgerApp =
|
||||||
|
LitecoinLedgerApp(_ledgerConnection!, derivationPath: walletInfo.derivationInfo!.derivationPath!);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<BtcTransaction> buildHardwareWalletTransaction({
|
||||||
|
required List<BitcoinBaseOutput> outputs,
|
||||||
|
required BigInt fee,
|
||||||
|
required BasedUtxoNetwork network,
|
||||||
|
required List<UtxoWithAddress> utxos,
|
||||||
|
required Map<String, PublicKeyWithDerivationPath> publicKeys,
|
||||||
|
String? memo,
|
||||||
|
bool enableRBF = false,
|
||||||
|
BitcoinOrdering inputOrdering = BitcoinOrdering.bip69,
|
||||||
|
BitcoinOrdering outputOrdering = BitcoinOrdering.bip69,
|
||||||
|
}) async {
|
||||||
|
final readyInputs = <LedgerTransaction>[];
|
||||||
|
for (final utxo in utxos) {
|
||||||
|
final rawTx = await electrumClient.getTransactionHex(hash: utxo.utxo.txHash);
|
||||||
|
final publicKeyAndDerivationPath = publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
|
||||||
|
|
||||||
|
readyInputs.add(LedgerTransaction(
|
||||||
|
rawTx: rawTx,
|
||||||
|
outputIndex: utxo.utxo.vout,
|
||||||
|
ownerPublicKey: Uint8List.fromList(hex.decode(publicKeyAndDerivationPath.publicKey)),
|
||||||
|
ownerDerivationPath: publicKeyAndDerivationPath.derivationPath,
|
||||||
|
// sequence: enableRBF ? 0x1 : 0xffffffff,
|
||||||
|
sequence: 0xffffffff,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
String? changePath;
|
||||||
|
for (final output in outputs) {
|
||||||
|
final maybeChangePath = publicKeys[(output as BitcoinOutput).address.pubKeyHash()];
|
||||||
|
if (maybeChangePath != null) changePath ??= maybeChangePath.derivationPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
final rawHex = await _litecoinLedgerApp!.createTransaction(
|
||||||
|
inputs: readyInputs,
|
||||||
|
outputs: outputs
|
||||||
|
.map((e) => TransactionOutput.fromBigInt(
|
||||||
|
(e as BitcoinOutput).value, Uint8List.fromList(e.address.toScriptPubKey().toBytes())))
|
||||||
|
.toList(),
|
||||||
|
changePath: changePath,
|
||||||
|
sigHashType: 0x01,
|
||||||
|
additionals: ["bech32"],
|
||||||
|
isSegWit: true,
|
||||||
|
useTrustedInputForSegwit: true
|
||||||
|
);
|
||||||
|
|
||||||
|
return BtcTransaction.fromRaw(rawHex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,17 @@ import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
part 'litecoin_wallet_addresses.g.dart';
|
part 'litecoin_wallet_addresses.g.dart';
|
||||||
|
|
||||||
class LitecoinWalletAddresses = LitecoinWalletAddressesBase with _$LitecoinWalletAddresses;
|
class LitecoinWalletAddresses = LitecoinWalletAddressesBase
|
||||||
|
with _$LitecoinWalletAddresses;
|
||||||
|
|
||||||
abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with Store {
|
abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses
|
||||||
|
with Store {
|
||||||
LitecoinWalletAddressesBase(
|
LitecoinWalletAddressesBase(
|
||||||
WalletInfo walletInfo, {
|
WalletInfo walletInfo, {
|
||||||
required super.mainHd,
|
required super.mainHd,
|
||||||
required super.sideHd,
|
required super.sideHd,
|
||||||
required super.network,
|
required super.network,
|
||||||
|
required super.isHardwareWallet,
|
||||||
required this.mwebHd,
|
required this.mwebHd,
|
||||||
required this.mwebEnabled,
|
required this.mwebEnabled,
|
||||||
super.initialAddresses,
|
super.initialAddresses,
|
||||||
|
@ -37,20 +40,20 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
||||||
print("initialized with ${mwebAddrs.length} mweb addresses");
|
print("initialized with ${mwebAddrs.length} mweb addresses");
|
||||||
}
|
}
|
||||||
|
|
||||||
final Bip32Slip10Secp256k1 mwebHd;
|
final Bip32Slip10Secp256k1? mwebHd;
|
||||||
bool mwebEnabled;
|
bool mwebEnabled;
|
||||||
int mwebTopUpIndex = 1000;
|
int mwebTopUpIndex = 1000;
|
||||||
List<String> mwebAddrs = [];
|
List<String> mwebAddrs = [];
|
||||||
bool generating = false;
|
bool generating = false;
|
||||||
|
|
||||||
List<int> get scanSecret => mwebHd.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw;
|
List<int> get scanSecret =>
|
||||||
|
mwebHd!.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw;
|
||||||
List<int> get spendPubkey =>
|
List<int> get spendPubkey =>
|
||||||
mwebHd.childKey(Bip32KeyIndex(0x80000001)).publicKey.pubKey.compressed;
|
mwebHd!.childKey(Bip32KeyIndex(0x80000001)).publicKey.pubKey.compressed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
await initMwebAddresses();
|
if (!isHardwareWallet) await initMwebAddresses();
|
||||||
await super.init();
|
await super.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +97,9 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
||||||
print("Done generating MWEB addresses len: ${mwebAddrs.length}");
|
print("Done generating MWEB addresses len: ${mwebAddrs.length}");
|
||||||
|
|
||||||
// ensure mweb addresses are up to date:
|
// ensure mweb addresses are up to date:
|
||||||
|
// This is the Case if the Litecoin Wallet is a hardware Wallet
|
||||||
|
if (mwebHd == null) return;
|
||||||
|
|
||||||
if (mwebAddresses.length < mwebAddrs.length) {
|
if (mwebAddresses.length < mwebAddrs.length) {
|
||||||
List<BitcoinAddressRecord> addressRecords = mwebAddrs
|
List<BitcoinAddressRecord> addressRecords = mwebAddrs
|
||||||
.asMap()
|
.asMap()
|
||||||
|
@ -143,7 +149,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
||||||
|
|
||||||
@action
|
@action
|
||||||
@override
|
@override
|
||||||
Future<String> getChangeAddress(
|
Future<BitcoinAddressRecord> getChangeAddress(
|
||||||
{List<BitcoinUnspent>? inputs, List<BitcoinOutput>? outputs, bool isPegIn = false}) async {
|
{List<BitcoinUnspent>? inputs, List<BitcoinOutput>? outputs, bool isPegIn = false}) async {
|
||||||
// use regular change address on peg in, otherwise use mweb for change address:
|
// use regular change address on peg in, otherwise use mweb for change address:
|
||||||
|
|
||||||
|
@ -187,7 +193,12 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
||||||
|
|
||||||
if (mwebEnabled) {
|
if (mwebEnabled) {
|
||||||
await ensureMwebAddressUpToIndexExists(1);
|
await ensureMwebAddressUpToIndexExists(1);
|
||||||
return mwebAddrs[0];
|
return BitcoinAddressRecord(
|
||||||
|
mwebAddrs[0],
|
||||||
|
index: 0,
|
||||||
|
type: SegwitAddresType.mweb,
|
||||||
|
network: network,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.getChangeAddress();
|
return super.getChangeAddress();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_mnemonics_bip39.dart';
|
import 'package:cw_bitcoin/bitcoin_mnemonics_bip39.dart';
|
||||||
import 'package:cw_bitcoin/mnemonic_is_incorrect_exception.dart';
|
import 'package:cw_bitcoin/mnemonic_is_incorrect_exception.dart';
|
||||||
import 'package:cw_core/encryption_file_utils.dart';
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
|
@ -20,7 +21,7 @@ class LitecoinWalletService extends WalletService<
|
||||||
BitcoinNewWalletCredentials,
|
BitcoinNewWalletCredentials,
|
||||||
BitcoinRestoreWalletFromSeedCredentials,
|
BitcoinRestoreWalletFromSeedCredentials,
|
||||||
BitcoinRestoreWalletFromWIFCredentials,
|
BitcoinRestoreWalletFromWIFCredentials,
|
||||||
BitcoinNewWalletCredentials> {
|
BitcoinRestoreWalletFromHardware> {
|
||||||
LitecoinWalletService(
|
LitecoinWalletService(
|
||||||
this.walletInfoSource, this.unspentCoinsInfoSource, this.alwaysScan, this.isDirect);
|
this.walletInfoSource, this.unspentCoinsInfoSource, this.alwaysScan, this.isDirect);
|
||||||
|
|
||||||
|
@ -147,9 +148,23 @@ class LitecoinWalletService extends WalletService<
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LitecoinWallet> restoreFromHardwareWallet(BitcoinNewWalletCredentials credentials) {
|
Future<LitecoinWallet> restoreFromHardwareWallet(BitcoinRestoreWalletFromHardware credentials,
|
||||||
throw UnimplementedError(
|
{bool? isTestnet}) async {
|
||||||
"Restoring a Litecoin wallet from a hardware wallet is not yet supported!");
|
final network = isTestnet == true ? LitecoinNetwork.testnet : LitecoinNetwork.mainnet;
|
||||||
|
credentials.walletInfo?.network = network.value;
|
||||||
|
credentials.walletInfo?.derivationInfo?.derivationPath =
|
||||||
|
credentials.hwAccountData.derivationPath;
|
||||||
|
|
||||||
|
final wallet = await LitecoinWallet(
|
||||||
|
password: credentials.password!,
|
||||||
|
xpub: credentials.hwAccountData.xpub,
|
||||||
|
walletInfo: credentials.walletInfo!,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
|
await wallet.save();
|
||||||
|
await wallet.init();
|
||||||
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -16,10 +16,6 @@ class PSBTTransactionBuild {
|
||||||
for (var i = 0; i < inputs.length; i++) {
|
for (var i = 0; i < inputs.length; i++) {
|
||||||
final input = inputs[i];
|
final input = inputs[i];
|
||||||
|
|
||||||
print(input.utxo.isP2tr());
|
|
||||||
print(input.utxo.isSegwit());
|
|
||||||
print(input.utxo.isP2shSegwit());
|
|
||||||
|
|
||||||
psbt.setInputPreviousTxId(i, Uint8List.fromList(hex.decode(input.utxo.txHash).reversed.toList()));
|
psbt.setInputPreviousTxId(i, Uint8List.fromList(hex.decode(input.utxo.txHash).reversed.toList()));
|
||||||
psbt.setInputOutputIndex(i, input.utxo.vout);
|
psbt.setInputOutputIndex(i, input.utxo.vout);
|
||||||
psbt.setInputSequence(i, enableRBF ? 0x1 : 0xffffffff);
|
psbt.setInputSequence(i, enableRBF ? 0x1 : 0xffffffff);
|
||||||
|
|
|
@ -101,6 +101,14 @@ packages:
|
||||||
url: "https://github.com/cake-tech/blockchain_utils"
|
url: "https://github.com/cake-tech/blockchain_utils"
|
||||||
source: git
|
source: git
|
||||||
version: "3.3.0"
|
version: "3.3.0"
|
||||||
|
bluez:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: bluez
|
||||||
|
sha256: "203a1924e818a9dd74af2b2c7a8f375ab8e5edf0e486bba8f90a0d8a17ed9fce"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.8.2"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -300,6 +308,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.3"
|
version: "1.0.3"
|
||||||
|
dbus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dbus
|
||||||
|
sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.10"
|
||||||
encrypt:
|
encrypt:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -361,19 +377,19 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.1+1"
|
version: "2.2.1+1"
|
||||||
flutter_reactive_ble:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_reactive_ble
|
|
||||||
sha256: "247e2efa76de203d1ba11335c13754b5b9d0504b5423e5b0c93a600f016b24e0"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "5.3.1"
|
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_web_bluetooth:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_web_bluetooth
|
||||||
|
sha256: "52ce64f65d7321c4bf6abfe9dac02fb888731339a5e0ad6de59fb916c20c9f02"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.3"
|
||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -387,14 +403,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0"
|
version: "4.0.0"
|
||||||
functional_data:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: functional_data
|
|
||||||
sha256: "76d17dc707c40e552014f5a49c0afcc3f1e3f05e800cd6b7872940bfe41a5039"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.0"
|
|
||||||
glob:
|
glob:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -550,29 +558,37 @@ packages:
|
||||||
ledger_bitcoin:
|
ledger_bitcoin:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "packages/ledger-bitcoin"
|
||||||
ref: HEAD
|
ref: HEAD
|
||||||
resolved-ref: f819d37e235e239c315e93856abbf5e5d3b71dab
|
resolved-ref: dbb5c4956949dc734af3fc8febdbabed89da72aa
|
||||||
url: "https://github.com/cake-tech/ledger-bitcoin"
|
url: "https://github.com/cake-tech/ledger-flutter-plus-plugins"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.2"
|
version: "0.0.3"
|
||||||
ledger_flutter:
|
ledger_flutter_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
name: ledger_flutter_plus
|
||||||
ref: cake-v3
|
sha256: ea3ed586e1697776dacf42ac979095f1ca3bd143bf007cbe5c78e09cb6943f42
|
||||||
resolved-ref: "66469ff9dffe2417c70ae7287c9d76d2fe7157a4"
|
|
||||||
url: "https://github.com/cake-tech/ledger-flutter.git"
|
|
||||||
source: git
|
|
||||||
version: "1.0.2"
|
|
||||||
ledger_usb:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: ledger_usb
|
|
||||||
sha256: "52c92d03a4cffe06c82921c8e2f79f3cdad6e1cf78e1e9ca35444196ff8f14c2"
|
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.2.5"
|
||||||
|
ledger_litecoin:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "packages/ledger-litecoin"
|
||||||
|
ref: HEAD
|
||||||
|
resolved-ref: dbb5c4956949dc734af3fc8febdbabed89da72aa
|
||||||
|
url: "https://github.com/cake-tech/ledger-flutter-plus-plugins"
|
||||||
|
source: git
|
||||||
|
version: "0.0.2"
|
||||||
|
ledger_usb_plus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: ledger_usb_plus
|
||||||
|
sha256: "21cc5d976cf7edb3518bd2a0c4164139cbb0817d2e4f2054707fc4edfdf9ce87"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -701,6 +717,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.0"
|
||||||
|
petitparser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: petitparser
|
||||||
|
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.2"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -773,30 +797,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.2"
|
version: "3.2.2"
|
||||||
reactive_ble_mobile:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: reactive_ble_mobile
|
|
||||||
sha256: "9ec2b4c9c725e439950838d551579750060258fbccd5536d0543b4d07d225798"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "5.3.1"
|
|
||||||
reactive_ble_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: reactive_ble_platform_interface
|
|
||||||
sha256: "632c92401a2d69c9b94bd48f8fd47488a7013f3d1f9b291884350291a4a81813"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "5.3.1"
|
|
||||||
rxdart:
|
rxdart:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: rxdart
|
name: rxdart
|
||||||
sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb"
|
sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.27.7"
|
version: "0.28.0"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -987,6 +995,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.2"
|
version: "1.3.2"
|
||||||
|
universal_ble:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: universal_ble
|
||||||
|
sha256: "0dfbd6b64bff3ad61ed7a895c232530d9614e9b01ab261a74433a43267edb7f3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.12.0"
|
||||||
|
universal_platform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: universal_platform
|
||||||
|
sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
unorm_dart:
|
unorm_dart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1043,6 +1067,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
|
xml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xml
|
||||||
|
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.5.0"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -24,16 +24,12 @@ dependencies:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitbox-flutter.git
|
url: https://github.com/cake-tech/bitbox-flutter.git
|
||||||
ref: Add-Support-For-OP-Return-data
|
ref: Add-Support-For-OP-Return-data
|
||||||
rxdart: ^0.27.5
|
rxdart: ^0.28.0
|
||||||
cryptography: ^2.0.5
|
cryptography: ^2.0.5
|
||||||
blockchain_utils:
|
blockchain_utils:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/blockchain_utils
|
url: https://github.com/cake-tech/blockchain_utils
|
||||||
ref: cake-update-v2
|
ref: cake-update-v2
|
||||||
ledger_flutter: ^1.0.1
|
|
||||||
ledger_bitcoin:
|
|
||||||
git:
|
|
||||||
url: https://github.com/cake-tech/ledger-bitcoin
|
|
||||||
cw_mweb:
|
cw_mweb:
|
||||||
path: ../cw_mweb
|
path: ../cw_mweb
|
||||||
grpc: ^3.2.4
|
grpc: ^3.2.4
|
||||||
|
@ -44,6 +40,15 @@ dependencies:
|
||||||
bech32:
|
bech32:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bech32.git
|
url: https://github.com/cake-tech/bech32.git
|
||||||
|
ledger_flutter_plus: ^1.4.1
|
||||||
|
ledger_bitcoin:
|
||||||
|
git:
|
||||||
|
url: https://github.com/cake-tech/ledger-flutter-plus-plugins
|
||||||
|
path: packages/ledger-bitcoin
|
||||||
|
ledger_litecoin:
|
||||||
|
git:
|
||||||
|
url: https://github.com/cake-tech/ledger-flutter-plus-plugins
|
||||||
|
path: packages/ledger-litecoin
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
@ -54,10 +59,6 @@ dev_dependencies:
|
||||||
hive_generator: ^1.1.3
|
hive_generator: ^1.1.3
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
ledger_flutter:
|
|
||||||
git:
|
|
||||||
url: https://github.com/cake-tech/ledger-flutter.git
|
|
||||||
ref: cake-v3
|
|
||||||
watcher: ^1.1.0
|
watcher: ^1.1.0
|
||||||
protobuf: ^3.1.0
|
protobuf: ^3.1.0
|
||||||
bitcoin_base:
|
bitcoin_base:
|
||||||
|
|
|
@ -58,6 +58,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
|
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
|
||||||
network: network,
|
network: network,
|
||||||
initialAddressPageType: addressPageType,
|
initialAddressPageType: addressPageType,
|
||||||
|
isHardwareWallet: walletInfo.isHardwareWallet,
|
||||||
);
|
);
|
||||||
autorun((_) {
|
autorun((_) {
|
||||||
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
|
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
|
||||||
|
|
|
@ -15,6 +15,7 @@ abstract class BitcoinCashWalletAddressesBase extends ElectrumWalletAddresses wi
|
||||||
required super.mainHd,
|
required super.mainHd,
|
||||||
required super.sideHd,
|
required super.sideHd,
|
||||||
required super.network,
|
required super.network,
|
||||||
|
required super.isHardwareWallet,
|
||||||
super.initialAddresses,
|
super.initialAddresses,
|
||||||
super.initialRegularAddressIndex,
|
super.initialRegularAddressIndex,
|
||||||
super.initialChangeAddressIndex,
|
super.initialChangeAddressIndex,
|
||||||
|
|
|
@ -8,6 +8,7 @@ enum DeviceConnectionType {
|
||||||
[bool isIOS = false]) {
|
[bool isIOS = false]) {
|
||||||
switch (walletType) {
|
switch (walletType) {
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
|
case WalletType.litecoin:
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
if (isIOS) return [DeviceConnectionType.ble];
|
if (isIOS) return [DeviceConnectionType.ble];
|
||||||
|
|
|
@ -2,26 +2,26 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:cw_core/hardware/hardware_account_data.dart';
|
import 'package:cw_core/hardware/hardware_account_data.dart';
|
||||||
import 'package:ledger_ethereum/ledger_ethereum.dart';
|
import 'package:ledger_ethereum/ledger_ethereum.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
|
|
||||||
class EVMChainHardwareWalletService {
|
class EVMChainHardwareWalletService {
|
||||||
EVMChainHardwareWalletService(this.ledger, this.device);
|
EVMChainHardwareWalletService(this.ledgerConnection);
|
||||||
|
|
||||||
final Ledger ledger;
|
final LedgerConnection ledgerConnection;
|
||||||
final LedgerDevice device;
|
|
||||||
|
|
||||||
Future<List<HardwareAccountData>> getAvailableAccounts({int index = 0, int limit = 5}) async {
|
Future<List<HardwareAccountData>> getAvailableAccounts(
|
||||||
final ethereumLedgerApp = EthereumLedgerApp(ledger);
|
{int index = 0, int limit = 5}) async {
|
||||||
|
final ethereumLedgerApp = EthereumLedgerApp(ledgerConnection);
|
||||||
|
|
||||||
final version = await ethereumLedgerApp.getVersion(device);
|
await ethereumLedgerApp.getVersion();
|
||||||
|
|
||||||
final accounts = <HardwareAccountData>[];
|
final accounts = <HardwareAccountData>[];
|
||||||
final indexRange = List.generate(limit, (i) => i + index);
|
final indexRange = List.generate(limit, (i) => i + index);
|
||||||
|
|
||||||
for (final i in indexRange) {
|
for (final i in indexRange) {
|
||||||
final derivationPath = "m/44'/60'/$i'/0/0";
|
final derivationPath = "m/44'/60'/$i'/0/0";
|
||||||
final address =
|
final address = await ethereumLedgerApp.getAccounts(
|
||||||
await ethereumLedgerApp.getAccounts(device, accountsDerivationPath: derivationPath);
|
accountsDerivationPath: derivationPath);
|
||||||
|
|
||||||
accounts.add(HardwareAccountData(
|
accounts.add(HardwareAccountData(
|
||||||
address: address.first,
|
address: address.first,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/output_info.dart';
|
import 'package:cw_core/output_info.dart';
|
||||||
import 'package:cw_evm/evm_chain_transaction_priority.dart';
|
import 'package:cw_evm/evm_chain_transaction_priority.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
|
||||||
|
|
||||||
class EVMChainTransactionCredentials {
|
class EVMChainTransactionCredentials {
|
||||||
EVMChainTransactionCredentials(
|
EVMChainTransactionCredentials(
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:cw_core/hardware/device_not_connected_exception.dart';
|
import 'package:cw_core/hardware/device_not_connected_exception.dart'
|
||||||
|
as exception;
|
||||||
import 'package:ledger_ethereum/ledger_ethereum.dart';
|
import 'package:ledger_ethereum/ledger_ethereum.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
import 'package:web3dart/crypto.dart';
|
import 'package:web3dart/crypto.dart';
|
||||||
import 'package:web3dart/web3dart.dart';
|
import 'package:web3dart/web3dart.dart';
|
||||||
|
|
||||||
class EvmLedgerCredentials extends CredentialsWithKnownAddress {
|
class EvmLedgerCredentials extends CredentialsWithKnownAddress {
|
||||||
final String _address;
|
final String _address;
|
||||||
|
|
||||||
Ledger? ledger;
|
|
||||||
LedgerDevice? ledgerDevice;
|
|
||||||
EthereumLedgerApp? ethereumLedgerApp;
|
EthereumLedgerApp? ethereumLedgerApp;
|
||||||
|
|
||||||
EvmLedgerCredentials(this._address);
|
EvmLedgerCredentials(this._address);
|
||||||
|
@ -19,25 +18,25 @@ class EvmLedgerCredentials extends CredentialsWithKnownAddress {
|
||||||
@override
|
@override
|
||||||
EthereumAddress get address => EthereumAddress.fromHex(_address);
|
EthereumAddress get address => EthereumAddress.fromHex(_address);
|
||||||
|
|
||||||
void setLedger(Ledger setLedger, [LedgerDevice? setLedgerDevice, String? derivationPath]) {
|
void setLedgerConnection(LedgerConnection connection,
|
||||||
ledger = setLedger;
|
[String? derivationPath]) {
|
||||||
ledgerDevice = setLedgerDevice;
|
ethereumLedgerApp = EthereumLedgerApp(connection,
|
||||||
ethereumLedgerApp =
|
derivationPath: derivationPath ?? "m/44'/60'/0'/0/0");
|
||||||
EthereumLedgerApp(ledger!, derivationPath: derivationPath ?? "m/44'/60'/0'/0/0");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MsgSignature signToEcSignature(Uint8List payload, {int? chainId, bool isEIP1559 = false}) =>
|
MsgSignature signToEcSignature(Uint8List payload,
|
||||||
throw UnimplementedError("EvmLedgerCredentials.signToEcSignature");
|
{int? chainId, bool isEIP1559 = false}) =>
|
||||||
|
throw UnimplementedError("EvmLedgerCredentials.signToEcSignature");
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<MsgSignature> signToSignature(Uint8List payload,
|
Future<MsgSignature> signToSignature(Uint8List payload,
|
||||||
{int? chainId, bool isEIP1559 = false}) async {
|
{int? chainId, bool isEIP1559 = false}) async {
|
||||||
if (ledgerDevice == null && ledger?.devices.isNotEmpty != true) {
|
if (ethereumLedgerApp == null) {
|
||||||
throw DeviceNotConnectedException();
|
throw exception.DeviceNotConnectedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
final sig = await ethereumLedgerApp!.signTransaction(device, payload);
|
final sig = await ethereumLedgerApp!.signTransaction(payload);
|
||||||
|
|
||||||
final v = sig[0].toInt();
|
final v = sig[0].toInt();
|
||||||
final r = bytesToHex(sig.sublist(1, 1 + 32));
|
final r = bytesToHex(sig.sublist(1, 1 + 32));
|
||||||
|
@ -65,14 +64,16 @@ class EvmLedgerCredentials extends CredentialsWithKnownAddress {
|
||||||
chainIdV = chainId != null ? (parity + (chainId * 2 + 35)) : parity;
|
chainIdV = chainId != null ? (parity + (chainId * 2 + 35)) : parity;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MsgSignature(BigInt.parse(r, radix: 16), BigInt.parse(s, radix: 16), chainIdV);
|
return MsgSignature(
|
||||||
|
BigInt.parse(r, radix: 16), BigInt.parse(s, radix: 16), chainIdV);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Uint8List> signPersonalMessage(Uint8List payload, {int? chainId}) async {
|
Future<Uint8List> signPersonalMessage(Uint8List payload,
|
||||||
if (isNotConnected) throw DeviceNotConnectedException();
|
{int? chainId}) async {
|
||||||
|
if (isNotConnected) throw exception.DeviceNotConnectedException();
|
||||||
|
|
||||||
final sig = await ethereumLedgerApp!.signMessage(device, payload);
|
final sig = await ethereumLedgerApp!.signMessage(payload);
|
||||||
|
|
||||||
final r = sig.sublist(1, 1 + 32);
|
final r = sig.sublist(1, 1 + 32);
|
||||||
final s = sig.sublist(1 + 32, 1 + 32 + 32);
|
final s = sig.sublist(1 + 32, 1 + 32 + 32);
|
||||||
|
@ -84,20 +85,22 @@ class EvmLedgerCredentials extends CredentialsWithKnownAddress {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Uint8List signPersonalMessageToUint8List(Uint8List payload, {int? chainId}) =>
|
Uint8List signPersonalMessageToUint8List(Uint8List payload, {int? chainId}) =>
|
||||||
throw UnimplementedError("EvmLedgerCredentials.signPersonalMessageToUint8List");
|
throw UnimplementedError(
|
||||||
|
"EvmLedgerCredentials.signPersonalMessageToUint8List");
|
||||||
|
|
||||||
Future<void> provideERC20Info(String erc20ContractAddress, int chainId) async {
|
Future<void> provideERC20Info(
|
||||||
if (isNotConnected) throw DeviceNotConnectedException();
|
String erc20ContractAddress, int chainId) async {
|
||||||
|
if (isNotConnected) throw exception.DeviceNotConnectedException();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ethereumLedgerApp!.getAndProvideERC20TokenInformation(device,
|
await ethereumLedgerApp!.getAndProvideERC20TokenInformation(
|
||||||
erc20ContractAddress: erc20ContractAddress, chainId: chainId);
|
erc20ContractAddress: erc20ContractAddress, chainId: chainId);
|
||||||
} on LedgerException catch (e) {
|
} catch (e) {
|
||||||
if (e.errorCode != -28672) rethrow;
|
print(e);
|
||||||
|
rethrow;
|
||||||
|
// if (e.errorCode != -28672) rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get isNotConnected => (ledgerDevice ?? ledger?.devices.firstOrNull) == null;
|
bool get isNotConnected => ethereumLedgerApp == null || ethereumLedgerApp!.connection.isDisconnected;
|
||||||
|
|
||||||
LedgerDevice get device => ledgerDevice ?? ledger!.devices.first;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,20 +25,17 @@ dependencies:
|
||||||
mobx: ^2.0.7+4
|
mobx: ^2.0.7+4
|
||||||
cw_core:
|
cw_core:
|
||||||
path: ../cw_core
|
path: ../cw_core
|
||||||
ledger_flutter: ^1.0.1
|
ledger_flutter_plus: ^1.4.1
|
||||||
ledger_ethereum:
|
ledger_ethereum:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/ledger-ethereum.git
|
url: https://github.com/cake-tech/ledger-flutter-plus-plugins
|
||||||
|
path: packages/ledger-ethereum
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
web3dart:
|
web3dart:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/web3dart.git
|
url: https://github.com/cake-tech/web3dart.git
|
||||||
ref: cake
|
ref: cake
|
||||||
ledger_flutter:
|
|
||||||
git:
|
|
||||||
url: https://github.com/cake-tech/ledger-flutter.git
|
|
||||||
ref: cake-v3
|
|
||||||
watcher: ^1.1.0
|
watcher: ^1.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
**N:B** Throughout this guide, `walletx` refers to the specific wallet type you want to add. If you're adding `BNB` to CakeWallet, then `walletx` for you here is `bnb`.
|
**N:B** Throughout this guide, `walletx` refers to the specific wallet type you want to add. If you're adding `BNB` to CakeWallet, then `walletx` for you here is `bnb`.
|
||||||
|
|
||||||
**Core Folder/Files Setup**
|
**Core Folder/Files Setup**
|
||||||
- Idenitify your core component/package (major project component), which would power the integration e.g web3dart, solana, onchain etc
|
- Identify your core component/package (major project component), which would power the integration e.g web3dart, solana, onchain etc
|
||||||
- Add a new entry to `WalletType` class in `cw_core/wallet_type.dart`.
|
- Add a new entry to `WalletType` class in `cw_core/wallet_type.dart`.
|
||||||
- Fill out the necessary information in the various functions in the files, concerning the wallet name, the native currency type, symbol etc.
|
- Fill out the necessary information in the various functions in the files, concerning the wallet name, the native currency type, symbol etc.
|
||||||
- Go to `cw_core/lib/currency_for_wallet_type.dart`, in the `currencyForWalletType` function, add a case for `walletx`, returning the native cryptocurrency for `walletx`.
|
- Go to `cw_core/lib/currency_for_wallet_type.dart`, in the `currencyForWalletType` function, add a case for `walletx`, returning the native cryptocurrency for `walletx`.
|
||||||
|
@ -144,7 +144,7 @@ You can add as many node entries as desired.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- Next, we’ll write the function to change walletX current node to default. An handy function we would make use of later on. Add a new preference key in `lib/entities/preference_key.dart` with the format `PreferencesKey.currentWalletXNodeIdKey`, we’ll use it to identify the current node id.
|
- Next, we’ll write the function to change walletX current node to default. A handy function we would make use of later on. Add a new preference key in `lib/entities/preference_key.dart` with the format `PreferencesKey.currentWalletXNodeIdKey`, we’ll use it to identify the current node id.
|
||||||
|
|
||||||
Future<void> changeWalletXCurrentNodeToDefault(
|
Future<void> changeWalletXCurrentNodeToDefault(
|
||||||
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
|
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
|
||||||
|
@ -228,7 +228,7 @@ Now you can run the codebase and successfully create a wallet for type walletX s
|
||||||
|
|
||||||
**Balance Screen**
|
**Balance Screen**
|
||||||
- Go to `lib/view_model/dashboard/balance_view_model.dart`
|
- Go to `lib/view_model/dashboard/balance_view_model.dart`
|
||||||
- Modify the function to adjust the way the balance is being display on the app: `isHomeScreenSettingsEnabled`
|
- Modify the function to adjust the way the balance is being displayed on the app: `isHomeScreenSettingsEnabled`
|
||||||
- Add a case to the `availableBalanceLabel` getter to modify the text being displayed (Available or confirmed)
|
- Add a case to the `availableBalanceLabel` getter to modify the text being displayed (Available or confirmed)
|
||||||
- Same for `additionalBalanceLabel`
|
- Same for `additionalBalanceLabel`
|
||||||
- Next, go to `lib/reactions/fiat_rate_update.dart`
|
- Next, go to `lib/reactions/fiat_rate_update.dart`
|
||||||
|
|
|
@ -57,7 +57,7 @@ Proceed into the source code before proceeding with the next steps:
|
||||||
|
|
||||||
### 7. Execute Build & Setup Commands for Cake Wallet
|
### 7. Execute Build & Setup Commands for Cake Wallet
|
||||||
|
|
||||||
We need to generate project settings like app name, app icon, package name, etc. For this need to setup environment variables and configure project files.
|
We need to generate project settings like app name, app icon, package name, etc. For this, we need to setup environment variables and configure project files.
|
||||||
|
|
||||||
Please pick what app you want to build: cakewallet or monero.com.
|
Please pick what app you want to build: cakewallet or monero.com.
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ Then we need to generate localization files and mobx models.
|
||||||
|
|
||||||
`$ flutter build ios --release`
|
`$ flutter build ios --release`
|
||||||
|
|
||||||
Then you can open `ios/Runner.xcworkspace` with Xcode and you can to archive the application.
|
Then you can open `ios/Runner.xcworkspace` with Xcode and you can archive the application.
|
||||||
|
|
||||||
Or if you want to run to connected device:
|
Or if you want to run to connected device:
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ Then install `Desktop development with C++` packages via Visual Studio 2022, or
|
||||||
- `C++ 2022 Redistributable Update`
|
- `C++ 2022 Redistributable Update`
|
||||||
- `C++ core desktop features`
|
- `C++ core desktop features`
|
||||||
- `MVC v143 - VS 2022 C++ x64/x86 build tools`
|
- `MVC v143 - VS 2022 C++ x64/x86 build tools`
|
||||||
- `C++ CMake tools for Windwos`
|
- `C++ CMake tools for Windows`
|
||||||
- `Testing tools core features - Build Tools`
|
- `Testing tools core features - Build Tools`
|
||||||
- `C++ AddressSanitizer`.
|
- `C++ AddressSanitizer`.
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ For building monero dependencies, it is required to install Windows WSL (https:/
|
||||||
|
|
||||||
### 5. Pull Cake Wallet source code
|
### 5. Pull Cake Wallet source code
|
||||||
|
|
||||||
You can downlaod CakeWallet source code from our [GitHub repository](github.com/cake-tech/cake_wallet) via git:
|
You can download CakeWallet source code from our [GitHub repository](github.com/cake-tech/cake_wallet) via git:
|
||||||
`$ git clone https://github.com/cake-tech/cake_wallet.git --branch MrCyjaneK-cyjan-monerodart`
|
`$ git clone https://github.com/cake-tech/cake_wallet.git --branch MrCyjaneK-cyjan-monerodart`
|
||||||
OR you can download it as [Zip archive](https://github.com/cake-tech/cake_wallet/archive/refs/heads/MrCyjaneK-cyjan-monerodart.zip)
|
OR you can download it as [Zip archive](https://github.com/cake-tech/cake_wallet/archive/refs/heads/MrCyjaneK-cyjan-monerodart.zip)
|
||||||
|
|
||||||
|
@ -52,6 +52,6 @@ For that you need to run the shell (bash - typically same named utility should b
|
||||||
|
|
||||||
To configure the application, open the directory where you have downloaded or unarchived Cake Wallet sources and run `cakewallet.bat`.
|
To configure the application, open the directory where you have downloaded or unarchived Cake Wallet sources and run `cakewallet.bat`.
|
||||||
Or if you used WSL and have active shell session you can run `$ ./cakewallet.sh` script in `scripts/windows` which will run `cakewallet.bat` in WSL.
|
Or if you used WSL and have active shell session you can run `$ ./cakewallet.sh` script in `scripts/windows` which will run `cakewallet.bat` in WSL.
|
||||||
After execution of `cakewallet.bat` you should to get `Cake Wallet.zip` in project root directory which will contains `CakeWallet.exe` file and another needed files for run the application. Now you can extract files from `Cake Wallet.zip` archive and run the application.
|
After execution of `cakewallet.bat` you should to get `Cake Wallet.zip` in project root directory which will contain `CakeWallet.exe` file and another needed files for run the application. Now you can extract files from `Cake Wallet.zip` archive and run the application.
|
||||||
|
|
||||||
Copyright (c) 2024 Cake Labs LLC.
|
Copyright (c) 2024 Cake Labs LLC.
|
||||||
|
|
|
@ -111,22 +111,12 @@ import workmanager
|
||||||
|
|
||||||
private func makeSecure() {
|
private func makeSecure() {
|
||||||
if (!self.window.subviews.contains(textField)) {
|
if (!self.window.subviews.contains(textField)) {
|
||||||
|
let view = UIView(frame: CGRect(x: 0, y: 0, width: textField.frame.self.width, height: textField.frame.self.height))
|
||||||
self.window.addSubview(textField)
|
self.window.addSubview(textField)
|
||||||
textField.centerYAnchor.constraint(equalTo: self.window.centerYAnchor).isActive = true
|
|
||||||
textField.centerXAnchor.constraint(equalTo: self.window.centerXAnchor).isActive = true
|
|
||||||
self.window.layer.superlayer?.addSublayer(textField.layer)
|
self.window.layer.superlayer?.addSublayer(textField.layer)
|
||||||
textField.layer.sublayers?.first?.addSublayer(self.window.layer)
|
textField.layer.sublayers?.last!.addSublayer(self.window.layer)
|
||||||
|
textField.leftView = view
|
||||||
|
textField.leftViewMode = .always
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// @objc override func applicationWillTerminate(_ notification: Notification) {
|
|
||||||
// super.applicationWillTerminate(application)
|
|
||||||
|
|
||||||
// // Call the stop method on your plugin
|
|
||||||
// if let plugin = self.registrar(forPlugin: "CwMwebPlugin")?.valuePublished(byPlugin: "CwMwebPlugin") as? CwMwebPlugin {
|
|
||||||
// plugin.stop()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -487,18 +487,30 @@ class CWBitcoin extends Bitcoin {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void setLedger(WalletBase wallet, Ledger ledger, LedgerDevice device) {
|
void setLedgerConnection(WalletBase wallet, ledger.LedgerConnection connection) {
|
||||||
(wallet as BitcoinWallet).setLedger(ledger, device);
|
(wallet as ElectrumWallet).setLedgerConnection(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM,
|
Future<List<HardwareAccountData>> getHardwareWalletBitcoinAccounts(LedgerViewModel ledgerVM,
|
||||||
{int index = 0, int limit = 5}) async {
|
{int index = 0, int limit = 5}) async {
|
||||||
final hardwareWalletService = BitcoinHardwareWalletService(ledgerVM.ledger, ledgerVM.device);
|
final hardwareWalletService = BitcoinHardwareWalletService(ledgerVM.connection);
|
||||||
try {
|
try {
|
||||||
return hardwareWalletService.getAvailableAccounts(index: index, limit: limit);
|
return hardwareWalletService.getAvailableAccounts(index: index, limit: limit);
|
||||||
} on LedgerException catch (err) {
|
} catch (err) {
|
||||||
print(err.message);
|
print(err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<HardwareAccountData>> getHardwareWalletLitecoinAccounts(LedgerViewModel ledgerVM,
|
||||||
|
{int index = 0, int limit = 5}) async {
|
||||||
|
final hardwareWalletService = LitecoinHardwareWalletService(ledgerVM.connection);
|
||||||
|
try {
|
||||||
|
return hardwareWalletService.getAvailableAccounts(index: index, limit: limit);
|
||||||
|
} catch (err) {
|
||||||
|
print(err);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,6 +256,9 @@ Future<void> defaultSettingsMigration(
|
||||||
await _addSethNode(nodes, sharedPreferences);
|
await _addSethNode(nodes, sharedPreferences);
|
||||||
await updateTronNodesWithNowNodes(sharedPreferences: sharedPreferences, nodes: nodes);
|
await updateTronNodesWithNowNodes(sharedPreferences: sharedPreferences, nodes: nodes);
|
||||||
break;
|
break;
|
||||||
|
case 42:
|
||||||
|
updateBtcElectrumNodeToUseSSL(nodes, sharedPreferences);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -270,6 +273,15 @@ Future<void> defaultSettingsMigration(
|
||||||
await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version);
|
await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateBtcElectrumNodeToUseSSL(Box<Node> nodes, SharedPreferences sharedPreferences) {
|
||||||
|
final btcElectrumNode = nodes.values.firstWhereOrNull((element) => element.uriRaw == newCakeWalletBitcoinUri);
|
||||||
|
|
||||||
|
if (btcElectrumNode != null) {
|
||||||
|
btcElectrumNode.useSSL = true;
|
||||||
|
btcElectrumNode.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _deselectQuantex(SharedPreferences sharedPreferences) {
|
void _deselectQuantex(SharedPreferences sharedPreferences) {
|
||||||
final Map<String, dynamic> exchangeProvidersSelection =
|
final Map<String, dynamic> exchangeProvidersSelection =
|
||||||
json.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}")
|
json.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}")
|
||||||
|
|
65
lib/entities/hardware_wallet/hardware_wallet_device.dart
Normal file
65
lib/entities/hardware_wallet/hardware_wallet_device.dart
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as ledger;
|
||||||
|
|
||||||
|
class HardwareWalletDevice {
|
||||||
|
final String name;
|
||||||
|
final HardwareWalletDeviceType type;
|
||||||
|
final HardwareWalletConnectionType connectionType;
|
||||||
|
|
||||||
|
const HardwareWalletDevice({
|
||||||
|
required this.name,
|
||||||
|
required this.type,
|
||||||
|
required this.connectionType,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory HardwareWalletDevice.fromLedgerDevice(ledger.LedgerDevice device) =>
|
||||||
|
HardwareWalletDevice(
|
||||||
|
name: device.name,
|
||||||
|
type: device.deviceInfo.toGeneric(),
|
||||||
|
connectionType: device.connectionType.toGeneric(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum HardwareWalletDeviceType {
|
||||||
|
ledgerBlue,
|
||||||
|
ledgerNanoS,
|
||||||
|
ledgerNanoX,
|
||||||
|
ledgerNanoSPlus,
|
||||||
|
ledgerStax,
|
||||||
|
ledgerFlex;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum HardwareWalletConnectionType {
|
||||||
|
usb,
|
||||||
|
ble,
|
||||||
|
nfc;
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ToGenericHardwareWalletDeviceType on ledger.LedgerDeviceType {
|
||||||
|
HardwareWalletDeviceType toGeneric() {
|
||||||
|
switch (this) {
|
||||||
|
case ledger.LedgerDeviceType.blue:
|
||||||
|
return HardwareWalletDeviceType.ledgerBlue;
|
||||||
|
case ledger.LedgerDeviceType.nanoS:
|
||||||
|
return HardwareWalletDeviceType.ledgerNanoS;
|
||||||
|
case ledger.LedgerDeviceType.nanoSP:
|
||||||
|
return HardwareWalletDeviceType.ledgerNanoSPlus;
|
||||||
|
case ledger.LedgerDeviceType.nanoX:
|
||||||
|
return HardwareWalletDeviceType.ledgerNanoX;
|
||||||
|
case ledger.LedgerDeviceType.stax:
|
||||||
|
return HardwareWalletDeviceType.ledgerStax;
|
||||||
|
case ledger.LedgerDeviceType.flex:
|
||||||
|
return HardwareWalletDeviceType.ledgerFlex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ToGenericHardwareWalletConnectionType on ledger.ConnectionType {
|
||||||
|
HardwareWalletConnectionType toGeneric() {
|
||||||
|
switch (this) {
|
||||||
|
case ledger.ConnectionType.usb:
|
||||||
|
return HardwareWalletConnectionType.usb;
|
||||||
|
case ledger.ConnectionType.ble:
|
||||||
|
return HardwareWalletConnectionType.ble;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -191,21 +191,21 @@ class CWEthereum extends Ethereum {
|
||||||
String getTokenAddress(CryptoCurrency asset) => (asset as Erc20Token).contractAddress;
|
String getTokenAddress(CryptoCurrency asset) => (asset as Erc20Token).contractAddress;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void setLedger(WalletBase wallet, Ledger ledger, LedgerDevice device) {
|
void setLedgerConnection(
|
||||||
((wallet as EVMChainWallet).evmChainPrivateKey as EvmLedgerCredentials).setLedger(
|
WalletBase wallet, ledger.LedgerConnection connection) {
|
||||||
ledger,
|
((wallet as EVMChainWallet).evmChainPrivateKey as EvmLedgerCredentials)
|
||||||
device.connectionType == ConnectionType.usb ? device : null,
|
.setLedgerConnection(
|
||||||
wallet.walletInfo.derivationInfo?.derivationPath);
|
connection, wallet.walletInfo.derivationInfo?.derivationPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM,
|
Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM,
|
||||||
{int index = 0, int limit = 5}) async {
|
{int index = 0, int limit = 5}) async {
|
||||||
final hardwareWalletService = EVMChainHardwareWalletService(ledgerVM.ledger, ledgerVM.device);
|
final hardwareWalletService = EVMChainHardwareWalletService(ledgerVM.connection);
|
||||||
try {
|
try {
|
||||||
return await hardwareWalletService.getAvailableAccounts(index: index, limit: limit);
|
return await hardwareWalletService.getAvailableAccounts(index: index, limit: limit);
|
||||||
} on LedgerException catch (err) {
|
} catch (err) {
|
||||||
print(err.message);
|
print(err);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||||
import 'package:cake_wallet/app_scroll_behavior.dart';
|
import 'package:cake_wallet/app_scroll_behavior.dart';
|
||||||
import 'package:cake_wallet/buy/order.dart';
|
import 'package:cake_wallet/buy/order.dart';
|
||||||
|
@ -43,6 +44,7 @@ import 'package:hive/hive.dart';
|
||||||
import 'package:cw_core/root_dir.dart';
|
import 'package:cw_core/root_dir.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:cw_core/window_size.dart';
|
import 'package:cw_core/window_size.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
final navigatorKey = GlobalKey<NavigatorState>();
|
final navigatorKey = GlobalKey<NavigatorState>();
|
||||||
final rootKey = GlobalKey<RootState>();
|
final rootKey = GlobalKey<RootState>();
|
||||||
|
@ -68,8 +70,18 @@ Future<void> runAppWithZone({Key? topLevelKey}) async {
|
||||||
};
|
};
|
||||||
await initializeAppAtRoot();
|
await initializeAppAtRoot();
|
||||||
|
|
||||||
runApp(App(key: topLevelKey));
|
if (kDebugMode) {
|
||||||
|
final appDocDir = await getAppDir();
|
||||||
|
|
||||||
|
final ledgerFile = File('${appDocDir.path}/ledger_log.txt');
|
||||||
|
if (!ledgerFile.existsSync()) ledgerFile.createSync();
|
||||||
|
Logger.root.onRecord.listen((event) async {
|
||||||
|
final content = ledgerFile.readAsStringSync();
|
||||||
|
ledgerFile.writeAsStringSync("$content\n${event.message}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
runApp(App(key: topLevelKey));
|
||||||
isAppRunning = true;
|
isAppRunning = true;
|
||||||
}, (error, stackTrace) async {
|
}, (error, stackTrace) async {
|
||||||
if (!isAppRunning) {
|
if (!isAppRunning) {
|
||||||
|
@ -193,7 +205,7 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
|
||||||
transactionDescriptions: transactionDescriptions,
|
transactionDescriptions: transactionDescriptions,
|
||||||
secureStorage: secureStorage,
|
secureStorage: secureStorage,
|
||||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||||
initialMigrationVersion: 41,
|
initialMigrationVersion: 42,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -190,20 +190,21 @@ class CWPolygon extends Polygon {
|
||||||
String getTokenAddress(CryptoCurrency asset) => (asset as Erc20Token).contractAddress;
|
String getTokenAddress(CryptoCurrency asset) => (asset as Erc20Token).contractAddress;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void setLedger(WalletBase wallet, Ledger ledger, LedgerDevice device) {
|
void setLedgerConnection(
|
||||||
((wallet as EVMChainWallet).evmChainPrivateKey as EvmLedgerCredentials).setLedger(
|
WalletBase wallet, ledger.LedgerConnection connection) {
|
||||||
ledger,
|
((wallet as EVMChainWallet).evmChainPrivateKey as EvmLedgerCredentials)
|
||||||
device.connectionType == ConnectionType.usb ? device : null,
|
.setLedgerConnection(
|
||||||
wallet.walletInfo.derivationInfo?.derivationPath);
|
connection, wallet.walletInfo.derivationInfo?.derivationPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM,
|
Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM,
|
||||||
{int index = 0, int limit = 5}) async {
|
{int index = 0, int limit = 5}) async {
|
||||||
final hardwareWalletService = EVMChainHardwareWalletService(ledgerVM.ledger, ledgerVM.device);
|
final hardwareWalletService = EVMChainHardwareWalletService(ledgerVM.connection);
|
||||||
try {
|
try {
|
||||||
return await hardwareWalletService.getAvailableAccounts(index: index, limit: limit);
|
return await hardwareWalletService.getAvailableAccounts(index: index, limit: limit);
|
||||||
} on LedgerException catch (err) {
|
} catch (err) {
|
||||||
|
print(err);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,14 @@ import 'dart:io';
|
||||||
|
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/connect_device/debug_device_page.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/connect_device/widgets/device_tile.dart';
|
import 'package:cake_wallet/src/screens/connect_device/widgets/device_tile.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
|
|
||||||
typedef OnConnectDevice = void Function(BuildContext, LedgerViewModel);
|
typedef OnConnectDevice = void Function(BuildContext, LedgerViewModel);
|
||||||
|
|
||||||
|
@ -19,7 +18,8 @@ class ConnectDevicePageParams {
|
||||||
final WalletType walletType;
|
final WalletType walletType;
|
||||||
final OnConnectDevice onConnectDevice;
|
final OnConnectDevice onConnectDevice;
|
||||||
|
|
||||||
ConnectDevicePageParams({required this.walletType, required this.onConnectDevice});
|
ConnectDevicePageParams(
|
||||||
|
{required this.walletType, required this.onConnectDevice});
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConnectDevicePage extends BasePage {
|
class ConnectDevicePage extends BasePage {
|
||||||
|
@ -35,7 +35,8 @@ class ConnectDevicePage extends BasePage {
|
||||||
String get title => S.current.restore_title_from_hardware_wallet;
|
String get title => S.current.restore_title_from_hardware_wallet;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) => ConnectDevicePageBody(walletType, onConnectDevice, ledgerVM);
|
Widget body(BuildContext context) =>
|
||||||
|
ConnectDevicePageBody(walletType, onConnectDevice, ledgerVM);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConnectDevicePageBody extends StatefulWidget {
|
class ConnectDevicePageBody extends StatefulWidget {
|
||||||
|
@ -43,47 +44,35 @@ class ConnectDevicePageBody extends StatefulWidget {
|
||||||
final OnConnectDevice onConnectDevice;
|
final OnConnectDevice onConnectDevice;
|
||||||
final LedgerViewModel ledgerVM;
|
final LedgerViewModel ledgerVM;
|
||||||
|
|
||||||
const ConnectDevicePageBody(this.walletType, this.onConnectDevice, this.ledgerVM);
|
const ConnectDevicePageBody(
|
||||||
|
this.walletType, this.onConnectDevice, this.ledgerVM);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ConnectDevicePageBodyState createState() => ConnectDevicePageBodyState();
|
ConnectDevicePageBodyState createState() => ConnectDevicePageBodyState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
final imageLedger = 'assets/images/ledger_nano.png';
|
|
||||||
|
|
||||||
final ledger = Ledger(
|
|
||||||
options: LedgerOptions(
|
|
||||||
scanMode: ScanMode.balanced,
|
|
||||||
maxScanDuration: const Duration(minutes: 5),
|
|
||||||
),
|
|
||||||
onPermissionRequest: (_) async {
|
|
||||||
Map<Permission, PermissionStatus> statuses = await [
|
|
||||||
Permission.bluetoothScan,
|
|
||||||
Permission.bluetoothConnect,
|
|
||||||
Permission.bluetoothAdvertise,
|
|
||||||
].request();
|
|
||||||
|
|
||||||
return statuses.values.where((status) => status.isDenied).isEmpty;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
var bleIsEnabled = true;
|
|
||||||
var bleDevices = <LedgerDevice>[];
|
var bleDevices = <LedgerDevice>[];
|
||||||
var usbDevices = <LedgerDevice>[];
|
var usbDevices = <LedgerDevice>[];
|
||||||
|
|
||||||
late Timer? _usbRefreshTimer = null;
|
late Timer? _usbRefreshTimer = null;
|
||||||
late Timer? _bleRefreshTimer = null;
|
late Timer? _bleRefreshTimer = null;
|
||||||
|
late Timer? _bleStateTimer = null;
|
||||||
late StreamSubscription<LedgerDevice>? _bleRefresh = null;
|
late StreamSubscription<LedgerDevice>? _bleRefresh = null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_bleRefreshTimer = Timer.periodic(Duration(seconds: 1), (_) => _refreshBleDevices());
|
_bleStateTimer = Timer.periodic(
|
||||||
|
Duration(seconds: 1), (_) => widget.ledgerVM.updateBleState());
|
||||||
|
|
||||||
|
_bleRefreshTimer =
|
||||||
|
Timer.periodic(Duration(seconds: 1), (_) => _refreshBleDevices());
|
||||||
|
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
_usbRefreshTimer = Timer.periodic(Duration(seconds: 1), (_) => _refreshUsbDevices());
|
_usbRefreshTimer =
|
||||||
|
Timer.periodic(Duration(seconds: 1), (_) => _refreshUsbDevices());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -91,35 +80,59 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_bleRefreshTimer?.cancel();
|
_bleRefreshTimer?.cancel();
|
||||||
|
_bleStateTimer?.cancel();
|
||||||
_usbRefreshTimer?.cancel();
|
_usbRefreshTimer?.cancel();
|
||||||
_bleRefresh?.cancel();
|
_bleRefresh?.cancel();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _refreshUsbDevices() async {
|
Future<void> _refreshUsbDevices() async {
|
||||||
final dev = await ledger.listUsbDevices();
|
final dev = await widget.ledgerVM.ledgerPlusUSB.devices;
|
||||||
if (usbDevices.length != dev.length) setState(() => usbDevices = dev);
|
if (usbDevices.length != dev.length) setState(() => usbDevices = dev);
|
||||||
|
// _usbRefresh = widget.ledgerVM
|
||||||
|
// .scanForUsbDevices()
|
||||||
|
// .listen((device) => setState(() => usbDevices.add(device)))
|
||||||
|
// ..onError((e) {
|
||||||
|
// throw e.toString();
|
||||||
|
// });
|
||||||
|
// Keep polling until the lfp lib gets updated
|
||||||
|
// _usbRefreshTimer?.cancel();
|
||||||
|
// _usbRefreshTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _refreshBleDevices() async {
|
Future<void> _refreshBleDevices() async {
|
||||||
try {
|
try {
|
||||||
_bleRefresh = ledger.scan().listen((device) => setState(() => bleDevices.add(device)))
|
_bleRefresh = widget.ledgerVM
|
||||||
|
.scanForBleDevices()
|
||||||
|
.listen((device) => setState(() => bleDevices.add(device)))
|
||||||
..onError((e) {
|
..onError((e) {
|
||||||
throw e.toString();
|
throw e.toString();
|
||||||
});
|
});
|
||||||
setState(() => bleIsEnabled = true);
|
|
||||||
_bleRefreshTimer?.cancel();
|
_bleRefreshTimer?.cancel();
|
||||||
_bleRefreshTimer = null;
|
_bleRefreshTimer = null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setState(() => bleIsEnabled = false);
|
print(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _connectToDevice(LedgerDevice device) async {
|
Future<void> _connectToDevice(LedgerDevice device) async {
|
||||||
await widget.ledgerVM.connectLedger(device);
|
await widget.ledgerVM.connectLedger(device, widget.walletType);
|
||||||
widget.onConnectDevice(context, widget.ledgerVM);
|
widget.onConnectDevice(context, widget.ledgerVM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _getDeviceTileLeading(LedgerDeviceType deviceInfo) {
|
||||||
|
switch (deviceInfo) {
|
||||||
|
case LedgerDeviceType.nanoX:
|
||||||
|
return 'assets/images/hardware_wallet/ledger_nano_x.png';
|
||||||
|
case LedgerDeviceType.stax:
|
||||||
|
return 'assets/images/hardware_wallet/ledger_stax.png';
|
||||||
|
case LedgerDeviceType.flex:
|
||||||
|
return 'assets/images/hardware_wallet/ledger_flex.png';
|
||||||
|
default:
|
||||||
|
return 'assets/images/hardware_wallet/ledger_nano_x.png';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Center(
|
return Center(
|
||||||
|
@ -139,7 +152,9 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
|
color: Theme.of(context)
|
||||||
|
.extension<CakeTextTheme>()!
|
||||||
|
.titleColor),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -152,18 +167,25 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
// title: "Debug Ledger",
|
// title: "Debug Ledger",
|
||||||
// leading: imageLedger,
|
// leading: imageLedger,
|
||||||
// ),
|
// ),
|
||||||
if (!bleIsEnabled)
|
Observer(
|
||||||
Padding(
|
builder: (_) => Offstage(
|
||||||
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
offstage: widget.ledgerVM.bleIsEnabled,
|
||||||
child: Text(
|
child: Padding(
|
||||||
S.of(context).ledger_please_enable_bluetooth,
|
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||||
style: TextStyle(
|
child: Text(
|
||||||
fontSize: 16,
|
S.of(context).ledger_please_enable_bluetooth,
|
||||||
fontWeight: FontWeight.w500,
|
style: TextStyle(
|
||||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
|
fontSize: 16,
|
||||||
textAlign: TextAlign.center,
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<CakeTextTheme>()!
|
||||||
|
.titleColor),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
|
||||||
if (bleDevices.length > 0) ...[
|
if (bleDevices.length > 0) ...[
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||||
|
@ -174,7 +196,9 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
color: Theme.of(context)
|
||||||
|
.extension<CakeTextTheme>()!
|
||||||
|
.titleColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -186,7 +210,7 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
child: DeviceTile(
|
child: DeviceTile(
|
||||||
onPressed: () => _connectToDevice(device),
|
onPressed: () => _connectToDevice(device),
|
||||||
title: device.name,
|
title: device.name,
|
||||||
leading: imageLedger,
|
leading: _getDeviceTileLeading(device.deviceInfo),
|
||||||
connectionType: device.connectionType,
|
connectionType: device.connectionType,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -203,7 +227,9 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
color: Theme.of(context)
|
||||||
|
.extension<CakeTextTheme>()!
|
||||||
|
.titleColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -215,7 +241,7 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||||
child: DeviceTile(
|
child: DeviceTile(
|
||||||
onPressed: () => _connectToDevice(device),
|
onPressed: () => _connectToDevice(device),
|
||||||
title: device.name,
|
title: device.name,
|
||||||
leading: imageLedger,
|
leading: _getDeviceTileLeading(device.deviceInfo),
|
||||||
connectionType: device.connectionType,
|
connectionType: device.connectionType,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
// import 'dart:convert';
|
// import 'dart:typed_data';
|
||||||
//
|
//
|
||||||
|
// import 'package:basic_utils/basic_utils.dart';
|
||||||
|
// import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
// import 'package:cake_wallet/src/screens/base_page.dart';
|
// import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
// import 'package:cake_wallet/src/screens/connect_device/widgets/device_tile.dart';
|
// import 'package:cake_wallet/src/screens/connect_device/widgets/device_tile.dart';
|
||||||
// import 'package:cake_wallet/src/widgets/primary_button.dart';
|
// import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
// import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
// import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
// import 'package:convert/convert.dart';
|
|
||||||
// import 'package:flutter/material.dart';
|
// import 'package:flutter/material.dart';
|
||||||
// import 'package:ledger_bitcoin/ledger_bitcoin.dart';
|
// import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
// import 'package:ledger_flutter/ledger_flutter.dart';
|
// import 'package:ledger_litecoin/ledger_litecoin.dart';
|
||||||
// import 'package:permission_handler/permission_handler.dart';
|
// import 'package:permission_handler/permission_handler.dart';
|
||||||
// import 'package:polyseed/polyseed.dart';
|
|
||||||
//
|
//
|
||||||
// class DebugDevicePage extends BasePage {
|
// class DebugDevicePage extends BasePage {
|
||||||
// @override
|
// @override
|
||||||
|
@ -50,7 +50,9 @@
|
||||||
// },
|
// },
|
||||||
// );
|
// );
|
||||||
//
|
//
|
||||||
// late BitcoinLedgerApp btc;
|
// // late BitcoinLedgerApp btc;
|
||||||
|
// late LitecoinLedgerApp ltc;
|
||||||
|
//
|
||||||
// var devices = <LedgerDevice>[];
|
// var devices = <LedgerDevice>[];
|
||||||
// var status = "";
|
// var status = "";
|
||||||
// var counter = 0;
|
// var counter = 0;
|
||||||
|
@ -59,7 +61,8 @@
|
||||||
// @override
|
// @override
|
||||||
// void initState() {
|
// void initState() {
|
||||||
// super.initState();
|
// super.initState();
|
||||||
// btc = BitcoinLedgerApp(ledger);
|
// // btc = BitcoinLedgerApp(ledger);
|
||||||
|
// ltc = LitecoinLedgerApp(ledger);
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// @override
|
// @override
|
||||||
|
@ -81,7 +84,7 @@
|
||||||
//
|
//
|
||||||
// @override
|
// @override
|
||||||
// Widget build(BuildContext context) {
|
// Widget build(BuildContext context) {
|
||||||
// final imageLedger = 'assets/images/ledger_nano.png';
|
// final imageLedger = 'assets/images/hardware_wallet/ledger_nano_x.png';
|
||||||
//
|
//
|
||||||
// return Center(
|
// return Center(
|
||||||
// child: Container(
|
// child: Container(
|
||||||
|
@ -99,40 +102,25 @@
|
||||||
// DebugButton(
|
// DebugButton(
|
||||||
// title: "Get Version",
|
// title: "Get Version",
|
||||||
// method: "Version",
|
// method: "Version",
|
||||||
// func: () async => await btc.getVersion(selectedDevice!),
|
// // func: () async => await btc.getVersion(selectedDevice!),
|
||||||
// ),
|
// func: () async => await ltc.getVersion(selectedDevice!),
|
||||||
// DebugButton(
|
|
||||||
// title: "Get Master Fingerprint",
|
|
||||||
// method: "Master Fingerprint",
|
|
||||||
// func: () async => hex.encode(await btc.getMasterFingerprint(selectedDevice!)),
|
|
||||||
// ),
|
|
||||||
// DebugButton(
|
|
||||||
// title: "Get XPub",
|
|
||||||
// method: "XPub",
|
|
||||||
// func: () async => await btc.getXPubKey(selectedDevice!, derivationPath: "m/84'/0'/$counter'"),
|
|
||||||
// ),
|
// ),
|
||||||
// DebugButton(
|
// DebugButton(
|
||||||
// title: "Get Wallet Address",
|
// title: "Get Wallet Address",
|
||||||
// method: "Wallet Address",
|
// method: "Wallet Address",
|
||||||
// func: () async {
|
// func: () async {
|
||||||
// setState(() => counter++);
|
// setState(() => counter++);
|
||||||
// final derivationPath = "m/84'/0'/$counter'/0/0";
|
// final derivationPath = "m/84'/2'/0'/0/0";
|
||||||
// return await btc.getAccounts(selectedDevice!, accountsDerivationPath: derivationPath);
|
// return await ltc.getAccounts(selectedDevice!,
|
||||||
|
// accountsDerivationPath: derivationPath);
|
||||||
|
// // return await btc.getAccounts(selectedDevice!, accountsDerivationPath: derivationPath);
|
||||||
// // return await ethereum!.getHardwareWalletAccounts(selectedDevice!);
|
// // return await ethereum!.getHardwareWalletAccounts(selectedDevice!);
|
||||||
// },
|
// },
|
||||||
// ),
|
// ),
|
||||||
// DebugButton(
|
// DebugButton(
|
||||||
// title: "Send Money",
|
// title: "Send Money",
|
||||||
// method: "Sig",
|
// method: "Raw Tx",
|
||||||
// func: () async {
|
// func: sendMoney
|
||||||
// final psbt = PsbtV2();
|
|
||||||
// final psbtBuf = base64.decode(
|
|
||||||
// "cHNidP8BAgQCAAAAAQQBAQEFAQIAAQ4gTW6k/cwKKu1u7m9oKr5ob7VcAC0IPkfaDitRi/FkD7sBDwQAAAAAARAE/////wEA/ekBAQAAAAABA9AYVQLI722H0osKMa/4dvMucrnKV1Myxtlp0l0BoOBDAQAAAAD/////ku6r2ABaHt9N26f/P4eMljX8t1f4lBcFfEwuNm/uXYoBAAAAAP////+YeAl8arEGKOcyrWJAYwSboyCstkhHN8zn7/vy7pkYTAEAAAAA/////wHlHgAAAAAAABYAFKdq0umSucBGVkl2MpT6Hgo/0a/xAkcwRAIgMkiJmNFbEi2I3CQYOwyV/JepCnFQRvj4xghkySpFcJMCIGAypkkWltfj+ucvqUIu27tusDAIAAB+rBhX/GV7hPlEASEDyLmWyTLjLfC9kn8pnW42jW5N6EJo5fObjWWEyfLDu9UCSDBFAiEAg9crVtwBPF+sWk+Th6pLwzDjJGItwsUCvoBPtmMTEb4CIDGuM7WOguV0TP21oidF3bSUZlEAjUHWfWzxLKw+3LofASEDfN16xKb70UZSeQyX5Tlh8iRq7np5Nlz9GYdcSU50sKwCSDBFAiEAvotOblaEiBptRWkvb6bj2MGyRjTphKLBLiHYmrRMTCgCIEKJH+z65uPSSz1NIb0d/u3bU9l0xcWk0idEsXjB+BIiASEDrAEiEtrSNKxbh6F/KPaCTafF2LVjCzb75WB+x4xSuoQAAAAAAQEf5R4AAAAAAAAWABSnatLpkrnARlZJdjKU+h4KP9Gv8SIGA3xMuxmPsBAm9aMEUBs3N46DB+Kdts3bZR/Wxt+uM0H4GKtN6bpUAACAAAAAgAAAAIAAAAAAAAAAAAABBBTk7bEOxYcdXDi1eeWraYDufm6eJgEDCOgDAAAAAAAAAAEEFDX3g/pnDXIfsRw8shK42NZn+SdpAQMIiBMAAAAAAAAiAgN8TLsZj7AQJvWjBFAbNzeOgwfinbbN22Uf1sbfrjNB+BirTem6VAAAgAAAAIAAAACAAAAAAAAAAAAA"
|
|
||||||
// );
|
|
||||||
// psbt.deserialize(psbtBuf);
|
|
||||||
// final result = await btc.signPsbt(selectedDevice!, psbt: psbt);
|
|
||||||
// return result.toHexString();
|
|
||||||
// },
|
|
||||||
// ),
|
// ),
|
||||||
// Padding(
|
// Padding(
|
||||||
// padding: EdgeInsets.only(top: 20),
|
// padding: EdgeInsets.only(top: 20),
|
||||||
|
@ -147,18 +135,18 @@
|
||||||
// ...devices
|
// ...devices
|
||||||
// .map(
|
// .map(
|
||||||
// (device) => Padding(
|
// (device) => Padding(
|
||||||
// padding: EdgeInsets.only(bottom: 20),
|
// padding: EdgeInsets.only(bottom: 20),
|
||||||
// child: DeviceTile(
|
// child: DeviceTile(
|
||||||
// onPressed: () {
|
// onPressed: () {
|
||||||
// setState(() => selectedDevice = device);
|
// setState(() => selectedDevice = device);
|
||||||
// ledger.connect(device);
|
// ledger.connect(device);
|
||||||
// },
|
// },
|
||||||
// title: device.name,
|
// title: device.name,
|
||||||
// leading: imageLedger,
|
// leading: imageLedger,
|
||||||
// connectionType: device.connectionType,
|
// connectionType: device.connectionType,
|
||||||
// ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
// )
|
// )
|
||||||
// .toList(),
|
// .toList(),
|
||||||
// PrimaryButton(
|
// PrimaryButton(
|
||||||
// text: "Refresh BLE",
|
// text: "Refresh BLE",
|
||||||
|
@ -188,6 +176,42 @@
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
// Future<String> sendMoney() async {
|
||||||
|
// final readyInputs = [
|
||||||
|
// LedgerTransaction(
|
||||||
|
// rawTx: "010000000001018c055c85c3724c98842d27712771dd0de139711f5940bba2df4615c5522184740000000017160014faf7f6dfb4e70798b92c93f33b4c51024491829df0ffffff022b05c70000000000160014f489f947fd13a1fb44ac168427081d3f30b6ce0cde9dd82e0000000017a914d5eca376cb49d65031220ff9093b7d407073ed0d8702483045022100f648c9f6a9b8f35b6ec29bbfae312c95ed3d56ce6a3f177d994efe90562ec4bd02205b82ce2c94bc0c9d152c3afc668b200bd82f48d6a14e83c66ba0f154cd5f69190121038f1dca119420d4aa7ad04af1c0d65304723789cccc56d335b18692390437f35900000000",
|
||||||
|
// outputIndex: 0,
|
||||||
|
// ownerPublicKey:
|
||||||
|
// HexUtils.decode("03b2e67958ed3356e329e05cf94c3bee6b20c17175ac3b2a1278e073bf44f5d6ec"),
|
||||||
|
// ownerDerivationPath: "m/84'/2'/0'/0/0",
|
||||||
|
// sequence: 0xffffffff,
|
||||||
|
// )
|
||||||
|
// ];
|
||||||
|
//
|
||||||
|
// final outputs = [
|
||||||
|
// BitcoinOutput(
|
||||||
|
// address: P2wpkhAddress.fromAddress(
|
||||||
|
// address: "ltc1qn0g5e36xaj07lqj6w9xn52ng07hud42g3jf5ps",
|
||||||
|
// network: LitecoinNetwork.mainnet),
|
||||||
|
// value: BigInt.from(1000000)),
|
||||||
|
// BitcoinOutput(
|
||||||
|
// address: P2wpkhAddress.fromAddress(
|
||||||
|
// address: "ltc1qrx29qz4ghu4j0xk37ptgk7034cwpmjyxhrcnk9",
|
||||||
|
// network: LitecoinNetwork.mainnet),
|
||||||
|
// value: BigInt.from(12042705)),
|
||||||
|
// ];
|
||||||
|
// return await ltc.createTransaction(selectedDevice!,
|
||||||
|
// inputs: readyInputs,
|
||||||
|
// outputs: outputs
|
||||||
|
// .map((e) => TransactionOutput.fromBigInt(
|
||||||
|
// e.value, Uint8List.fromList(e.address.toScriptPubKey().toBytes())))
|
||||||
|
// .toList(),
|
||||||
|
// sigHashType: 0x01,
|
||||||
|
// additionals: ["bech32"],
|
||||||
|
// isSegWit: true,
|
||||||
|
// useTrustedInputForSegwit: true);
|
||||||
|
// }
|
||||||
|
//
|
||||||
// Widget DebugButton(
|
// Widget DebugButton(
|
||||||
// {required String title, required String method, required Future<dynamic> Function() func}) {
|
// {required String title, required String method, required Future<dynamic> Function() func}) {
|
||||||
// return Padding(
|
// return Padding(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:cake_wallet/themes/extensions/option_tile_theme.dart';
|
import 'package:cake_wallet/themes/extensions/option_tile_theme.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
|
|
||||||
class DeviceTile extends StatelessWidget {
|
class DeviceTile extends StatelessWidget {
|
||||||
const DeviceTile({
|
const DeviceTile({
|
||||||
|
|
|
@ -188,7 +188,7 @@ class CryptoBalanceWidget extends StatelessWidget {
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
'assets/images/ledger_nano.png',
|
'assets/images/hardware_wallet/ledger_nano_x.png',
|
||||||
width: 24,
|
width: 24,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.extension<DashboardPageTheme>()!
|
.extension<DashboardPageTheme>()!
|
||||||
|
|
|
@ -67,7 +67,7 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> {
|
||||||
final mainImageColor = Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor;
|
final mainImageColor = Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor;
|
||||||
final brightImageColor = Theme.of(context).extension<InfoTheme>()!.textColor;
|
final brightImageColor = Theme.of(context).extension<InfoTheme>()!.textColor;
|
||||||
final imageColor = widget.themeType == ThemeType.bright ? brightImageColor : mainImageColor;
|
final imageColor = widget.themeType == ThemeType.bright ? brightImageColor : mainImageColor;
|
||||||
final imageLedger = Image.asset('assets/images/ledger_nano.png', width: 40, color: imageColor);
|
final imageLedger = Image.asset('assets/images/hardware_wallet/ledger_nano_x.png', width: 40, color: imageColor);
|
||||||
final imageSeedKeys = Image.asset('assets/images/restore_wallet_image.png', color: imageColor);
|
final imageSeedKeys = Image.asset('assets/images/restore_wallet_image.png', color: imageColor);
|
||||||
final imageBackup = Image.asset('assets/images/backup.png', color: imageColor);
|
final imageBackup = Image.asset('assets/images/backup.png', color: imageColor);
|
||||||
|
|
||||||
|
@ -186,4 +186,4 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -395,16 +395,19 @@ class SendPage extends BasePage {
|
||||||
|
|
||||||
if (sendViewModel.wallet.isHardwareWallet) {
|
if (sendViewModel.wallet.isHardwareWallet) {
|
||||||
if (!sendViewModel.ledgerViewModel!.isConnected) {
|
if (!sendViewModel.ledgerViewModel!.isConnected) {
|
||||||
await Navigator.of(context).pushNamed(Routes.connectDevices,
|
await Navigator.of(context).pushNamed(
|
||||||
|
Routes.connectDevices,
|
||||||
arguments: ConnectDevicePageParams(
|
arguments: ConnectDevicePageParams(
|
||||||
walletType: sendViewModel.walletType,
|
walletType: sendViewModel.walletType,
|
||||||
onConnectDevice: (BuildContext context, _) {
|
onConnectDevice: (BuildContext context, _) {
|
||||||
sendViewModel.ledgerViewModel!.setLedger(sendViewModel.wallet);
|
sendViewModel.ledgerViewModel!
|
||||||
|
.setLedger(sendViewModel.wallet);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
sendViewModel.ledgerViewModel!.setLedger(sendViewModel.wallet);
|
sendViewModel.ledgerViewModel!
|
||||||
|
.setLedger(sendViewModel.wallet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,7 +512,7 @@ class SendPage extends BasePage {
|
||||||
if (state is TransactionCommitted) {
|
if (state is TransactionCommitted) {
|
||||||
newContactAddress =
|
newContactAddress =
|
||||||
newContactAddress ?? sendViewModel.newContactAddress();
|
newContactAddress ?? sendViewModel.newContactAddress();
|
||||||
|
|
||||||
if (sendViewModel.coinTypeToSpendFrom != UnspentCoinType.any) {
|
if (sendViewModel.coinTypeToSpendFrom != UnspentCoinType.any) {
|
||||||
newContactAddress = null;
|
newContactAddress = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -435,7 +435,7 @@ abstract class DashboardViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get hasMweb => wallet.type == WalletType.litecoin && (Platform.isIOS || Platform.isAndroid);
|
bool get hasMweb => wallet.type == WalletType.litecoin && (Platform.isIOS || Platform.isAndroid) && !wallet.isHardwareWallet;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get showMwebCard => hasMweb && settingsStore.mwebCardDisplay && !mwebEnabled;
|
bool get showMwebCard => hasMweb && settingsStore.mwebCardDisplay && !mwebEnabled;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
|
@ -9,11 +10,19 @@ import 'package:cake_wallet/wallet_type_utils.dart';
|
||||||
import 'package:cw_core/hardware/device_connection_type.dart';
|
import 'package:cw_core/hardware/device_connection_type.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
|
||||||
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as sdk;
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
||||||
class LedgerViewModel {
|
part 'ledger_view_model.g.dart';
|
||||||
late final Ledger ledger;
|
|
||||||
|
class LedgerViewModel = LedgerViewModelBase with _$LedgerViewModel;
|
||||||
|
|
||||||
|
abstract class LedgerViewModelBase with Store {
|
||||||
|
// late final Ledger ledger;
|
||||||
|
late final sdk.LedgerInterface ledgerPlusBLE;
|
||||||
|
late final sdk.LedgerInterface ledgerPlusUSB;
|
||||||
|
|
||||||
bool get _doesSupportHardwareWallets {
|
bool get _doesSupportHardwareWallets {
|
||||||
if (!DeviceInfo.instance.isMobile) {
|
if (!DeviceInfo.instance.isMobile) {
|
||||||
|
@ -21,53 +30,97 @@ class LedgerViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isMoneroOnly) {
|
if (isMoneroOnly) {
|
||||||
return DeviceConnectionType.supportedConnectionTypes(WalletType.monero, Platform.isIOS)
|
return DeviceConnectionType.supportedConnectionTypes(
|
||||||
|
WalletType.monero, Platform.isIOS)
|
||||||
.isNotEmpty;
|
.isNotEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LedgerViewModel() {
|
LedgerViewModelBase() {
|
||||||
if (_doesSupportHardwareWallets) {
|
if (_doesSupportHardwareWallets) {
|
||||||
ledger = Ledger(
|
reaction((_) => bleIsEnabled, (_) {
|
||||||
options: LedgerOptions(
|
if (bleIsEnabled) _initBLE();
|
||||||
scanMode: ScanMode.balanced,
|
});
|
||||||
maxScanDuration: const Duration(minutes: 5),
|
updateBleState();
|
||||||
),
|
|
||||||
onPermissionRequest: (_) async {
|
|
||||||
Map<Permission, PermissionStatus> statuses = await [
|
|
||||||
Permission.bluetoothScan,
|
|
||||||
Permission.bluetoothConnect,
|
|
||||||
Permission.bluetoothAdvertise,
|
|
||||||
].request();
|
|
||||||
|
|
||||||
return statuses.values.where((status) => status.isDenied).isEmpty;
|
if (!Platform.isIOS) {
|
||||||
},
|
ledgerPlusUSB = sdk.LedgerInterface.usb();
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> connectLedger(LedgerDevice device) async {
|
@observable
|
||||||
await ledger.connect(device);
|
bool bleIsEnabled = false;
|
||||||
|
|
||||||
if (device.connectionType == ConnectionType.usb) _device = device;
|
bool _bleIsInitialized = false;
|
||||||
|
Future<void> _initBLE() async {
|
||||||
|
if (bleIsEnabled && !_bleIsInitialized) {
|
||||||
|
ledgerPlusBLE = sdk.LedgerInterface.ble(onPermissionRequest: (_) async {
|
||||||
|
Map<Permission, PermissionStatus> statuses = await [
|
||||||
|
Permission.bluetoothScan,
|
||||||
|
Permission.bluetoothConnect,
|
||||||
|
Permission.bluetoothAdvertise,
|
||||||
|
].request();
|
||||||
|
|
||||||
|
return statuses.values.where((status) => status.isDenied).isEmpty;
|
||||||
|
});
|
||||||
|
_bleIsInitialized = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LedgerDevice? _device;
|
Future<void> updateBleState() async {
|
||||||
|
final bleState = await sdk.UniversalBle.getBluetoothAvailabilityState();
|
||||||
|
|
||||||
bool get isConnected => ledger.devices.isNotEmpty || _device != null;
|
final newState = bleState == sdk.AvailabilityState.poweredOn;
|
||||||
|
|
||||||
LedgerDevice get device => _device ?? ledger.devices.first;
|
if (newState != bleIsEnabled) bleIsEnabled = newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<sdk.LedgerDevice> scanForBleDevices() => ledgerPlusBLE.scan();
|
||||||
|
|
||||||
|
Stream<sdk.LedgerDevice> scanForUsbDevices() => ledgerPlusUSB.scan();
|
||||||
|
|
||||||
|
Future<void> connectLedger(sdk.LedgerDevice device, WalletType type) async {
|
||||||
|
if (isConnected) {
|
||||||
|
try {
|
||||||
|
await _connection!.disconnect();
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
final ledger = device.connectionType == sdk.ConnectionType.ble
|
||||||
|
? ledgerPlusBLE
|
||||||
|
: ledgerPlusUSB;
|
||||||
|
|
||||||
|
if (_connectionChangeListener == null) {
|
||||||
|
_connectionChangeListener = ledger.deviceStateChanges.listen((event) {
|
||||||
|
print('Ledger Device State Changed: $event');
|
||||||
|
if (event == sdk.BleConnectionState.disconnected) {
|
||||||
|
_connection = null;
|
||||||
|
_connectionChangeListener?.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_connection = await ledger.connect(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamSubscription<sdk.BleConnectionState>? _connectionChangeListener;
|
||||||
|
sdk.LedgerConnection? _connection;
|
||||||
|
|
||||||
|
bool get isConnected => _connection != null && !(_connection!.isDisconnected);
|
||||||
|
|
||||||
|
sdk.LedgerConnection get connection => _connection!;
|
||||||
|
|
||||||
void setLedger(WalletBase wallet) {
|
void setLedger(WalletBase wallet) {
|
||||||
switch (wallet.type) {
|
switch (wallet.type) {
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
return bitcoin!.setLedger(wallet, ledger, device);
|
case WalletType.litecoin:
|
||||||
|
return bitcoin!.setLedgerConnection(wallet, connection);
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
return ethereum!.setLedger(wallet, ledger, device);
|
return ethereum!.setLedgerConnection(wallet, connection);
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
return polygon!.setLedger(wallet, ledger, device);
|
return polygon!.setLedgerConnection(wallet, connection);
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected wallet type: ${wallet.type}');
|
throw Exception('Unexpected wallet type: ${wallet.type}');
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import 'package:cw_core/unspent_coin_type.dart';
|
||||||
import 'package:cake_wallet/view_model/send/output.dart';
|
import 'package:cake_wallet/view_model/send/output.dart';
|
||||||
import 'package:cake_wallet/view_model/send/send_template_view_model.dart';
|
import 'package:cake_wallet/view_model/send/send_template_view_model.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cake_wallet/entities/template.dart';
|
import 'package:cake_wallet/entities/template.dart';
|
||||||
import 'package:cake_wallet/core/address_validator.dart';
|
import 'package:cake_wallet/core/address_validator.dart';
|
||||||
|
@ -408,16 +407,16 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
state = ExecutedSuccessfullyState();
|
state = ExecutedSuccessfullyState();
|
||||||
return pendingTransaction;
|
return pendingTransaction;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e is LedgerException) {
|
// if (e is LedgerException) {
|
||||||
final errorCode = e.errorCode.toRadixString(16);
|
// final errorCode = e.errorCode.toRadixString(16);
|
||||||
final fallbackMsg =
|
// final fallbackMsg =
|
||||||
e.message.isNotEmpty ? e.message : "Unexpected Ledger Error Code: $errorCode";
|
// e.message.isNotEmpty ? e.message : "Unexpected Ledger Error Code: $errorCode";
|
||||||
final errorMsg = ledgerViewModel!.interpretErrorCode(errorCode) ?? fallbackMsg;
|
// final errorMsg = ledgerViewModel!.interpretErrorCode(errorCode) ?? fallbackMsg;
|
||||||
|
//
|
||||||
state = FailureState(errorMsg);
|
// state = FailureState(errorMsg);
|
||||||
} else {
|
// } else {
|
||||||
state = FailureState(translateErrorMessage(e, wallet.type, wallet.currency));
|
state = FailureState(translateErrorMessage(e, wallet.type, wallet.currency));
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,18 +83,19 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showRecipientAddress && !isRecipientAddressShown) {
|
final descriptionKey =
|
||||||
try {
|
'${transactionInfo.txHash}_${wallet.walletAddresses.primaryAddress}';
|
||||||
final recipientAddress = transactionDescriptionBox.values
|
final description = transactionDescriptionBox.values.firstWhere(
|
||||||
.firstWhere((val) => val.id == transactionInfo.txHash)
|
(val) => val.id == descriptionKey || val.id == transactionInfo.txHash,
|
||||||
.recipientAddress;
|
orElse: () => TransactionDescription(id: descriptionKey));
|
||||||
|
|
||||||
if (recipientAddress?.isNotEmpty ?? false) {
|
if (showRecipientAddress && !isRecipientAddressShown) {
|
||||||
items.add(StandartListItem(
|
final recipientAddress = description.recipientAddress;
|
||||||
title: S.current.transaction_details_recipient_address, value: recipientAddress!));
|
|
||||||
}
|
if (recipientAddress?.isNotEmpty ?? false) {
|
||||||
} catch (_) {
|
items.add(StandartListItem(
|
||||||
// FIX-ME: Unhandled exception
|
title: S.current.transaction_details_recipient_address,
|
||||||
|
value: recipientAddress!));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,12 +111,6 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
final descriptionKey = '${transactionInfo.txHash}_${wallet.walletAddresses.primaryAddress}';
|
|
||||||
|
|
||||||
final description = transactionDescriptionBox.values.firstWhere(
|
|
||||||
(val) => val.id == descriptionKey || val.id == transactionInfo.txHash,
|
|
||||||
orElse: () => TransactionDescription(id: descriptionKey));
|
|
||||||
|
|
||||||
items.add(TextFieldListItem(
|
items.add(TextFieldListItem(
|
||||||
title: S.current.note_tap_to_change,
|
title: S.current.note_tap_to_change,
|
||||||
value: description.note,
|
value: description.note,
|
||||||
|
|
|
@ -13,7 +13,6 @@ import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
part 'wallet_hardware_restore_view_model.g.dart';
|
part 'wallet_hardware_restore_view_model.g.dart';
|
||||||
|
@ -58,7 +57,11 @@ abstract class WalletHardwareRestoreViewModelBase extends WalletCreationVM with
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
accounts = await bitcoin!
|
accounts = await bitcoin!
|
||||||
.getHardwareWalletAccounts(ledgerViewModel, index: _nextIndex, limit: limit);
|
.getHardwareWalletBitcoinAccounts(ledgerViewModel, index: _nextIndex, limit: limit);
|
||||||
|
break;
|
||||||
|
case WalletType.litecoin:
|
||||||
|
accounts = await bitcoin!
|
||||||
|
.getHardwareWalletLitecoinAccounts(ledgerViewModel, index: _nextIndex, limit: limit);
|
||||||
break;
|
break;
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
accounts = await ethereum!
|
accounts = await ethereum!
|
||||||
|
@ -74,9 +77,10 @@ abstract class WalletHardwareRestoreViewModelBase extends WalletCreationVM with
|
||||||
|
|
||||||
availableAccounts.addAll(accounts);
|
availableAccounts.addAll(accounts);
|
||||||
_nextIndex += limit;
|
_nextIndex += limit;
|
||||||
} on LedgerException catch (e) {
|
// } on LedgerException catch (e) {
|
||||||
error = ledgerViewModel.interpretErrorCode(e.errorCode.toRadixString(16));
|
// error = ledgerViewModel.interpretErrorCode(e.errorCode.toRadixString(16));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
error = S.current.ledger_connection_error;
|
error = S.current.ledger_connection_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +93,7 @@ abstract class WalletHardwareRestoreViewModelBase extends WalletCreationVM with
|
||||||
WalletCredentials credentials;
|
WalletCredentials credentials;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
|
case WalletType.litecoin:
|
||||||
credentials =
|
credentials =
|
||||||
bitcoin!.createBitcoinHardwareWalletCredentials(name: name, accountData: selectedAccount!);
|
bitcoin!.createBitcoinHardwareWalletCredentials(name: name, accountData: selectedAccount!);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -17,6 +17,7 @@ import package_info_plus
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
import share_plus
|
import share_plus
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
|
import universal_ble
|
||||||
import url_launcher_macos
|
import url_launcher_macos
|
||||||
import wakelock_plus
|
import wakelock_plus
|
||||||
|
|
||||||
|
@ -33,6 +34,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
|
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
|
UniversalBlePlugin.register(with: registry.registrar(forPlugin: "UniversalBlePlugin"))
|
||||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
|
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ dependencies:
|
||||||
version: 4.0.2
|
version: 4.0.2
|
||||||
shared_preferences: ^2.0.15
|
shared_preferences: ^2.0.15
|
||||||
# provider: ^6.0.3
|
# provider: ^6.0.3
|
||||||
rxdart: ^0.27.4
|
rxdart: ^0.28.0
|
||||||
yaml: ^3.1.1
|
yaml: ^3.1.1
|
||||||
#barcode_scan: any
|
#barcode_scan: any
|
||||||
barcode_scan2: ^4.2.1
|
barcode_scan2: ^4.2.1
|
||||||
|
@ -99,7 +99,7 @@ dependencies:
|
||||||
polyseed: ^0.0.6
|
polyseed: ^0.0.6
|
||||||
nostr_tools: ^1.0.9
|
nostr_tools: ^1.0.9
|
||||||
solana: ^0.30.1
|
solana: ^0.30.1
|
||||||
ledger_flutter: ^1.0.1
|
ledger_flutter_plus: ^1.4.1
|
||||||
hashlib: ^1.19.2
|
hashlib: ^1.19.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
@ -127,10 +127,6 @@ dependency_overrides:
|
||||||
bech32:
|
bech32:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bech32.git
|
url: https://github.com/cake-tech/bech32.git
|
||||||
ledger_flutter:
|
|
||||||
git:
|
|
||||||
url: https://github.com/cake-tech/ledger-flutter.git
|
|
||||||
ref: cake-v3
|
|
||||||
web3dart:
|
web3dart:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/web3dart.git
|
url: https://github.com/cake-tech/web3dart.git
|
||||||
|
@ -157,6 +153,7 @@ flutter:
|
||||||
assets:
|
assets:
|
||||||
- assets/images/
|
- assets/images/
|
||||||
- assets/images/flags/
|
- assets/images/flags/
|
||||||
|
- assets/images/hardware_wallet/
|
||||||
- assets/node_list.yml
|
- assets/node_list.yml
|
||||||
- assets/haven_node_list.yml
|
- assets/haven_node_list.yml
|
||||||
- assets/bitcoin_electrum_server_list.yml
|
- assets/bitcoin_electrum_server_list.yml
|
||||||
|
|
|
@ -97,7 +97,7 @@
|
||||||
"cake_pay_account_note": "Melden Sie sich nur mit einer E-Mail-Adresse an, um Karten anzuzeigen und zu kaufen. Einige sind sogar mit Rabatt erhältlich!",
|
"cake_pay_account_note": "Melden Sie sich nur mit einer E-Mail-Adresse an, um Karten anzuzeigen und zu kaufen. Einige sind sogar mit Rabatt erhältlich!",
|
||||||
"cake_pay_learn_more": "Kaufen und lösen Sie Geschenkkarten sofort in der App ein!\nWischen Sie von links nach rechts, um mehr zu erfahren.",
|
"cake_pay_learn_more": "Kaufen und lösen Sie Geschenkkarten sofort in der App ein!\nWischen Sie von links nach rechts, um mehr zu erfahren.",
|
||||||
"cake_pay_save_order": "Die Karte sollte innerhalb von 1 Werktag an Ihre E-Mail gesendet werden, \n Ihre Bestell-ID zu speichern:",
|
"cake_pay_save_order": "Die Karte sollte innerhalb von 1 Werktag an Ihre E-Mail gesendet werden, \n Ihre Bestell-ID zu speichern:",
|
||||||
"cake_pay_subtitle": "Kaufen Sie weltweite Prepaid -Karten und Geschenkkarten",
|
"cake_pay_subtitle": "Kaufen Sie weltweite Prepaid-Karten und Geschenkkarten",
|
||||||
"cake_pay_web_cards_subtitle": "Kaufen Sie weltweit Prepaid-Karten und Geschenkkarten",
|
"cake_pay_web_cards_subtitle": "Kaufen Sie weltweit Prepaid-Karten und Geschenkkarten",
|
||||||
"cake_pay_web_cards_title": "Cake Pay-Webkarten",
|
"cake_pay_web_cards_title": "Cake Pay-Webkarten",
|
||||||
"cake_wallet": "Cake Wallet",
|
"cake_wallet": "Cake Wallet",
|
||||||
|
@ -114,7 +114,7 @@
|
||||||
"change_currency": "Währung ändern",
|
"change_currency": "Währung ändern",
|
||||||
"change_current_node": "Möchten Sie den aktuellen Knoten wirklich zu ${node}? ändern?",
|
"change_current_node": "Möchten Sie den aktuellen Knoten wirklich zu ${node}? ändern?",
|
||||||
"change_current_node_title": "Aktuellen Knoten ändern",
|
"change_current_node_title": "Aktuellen Knoten ändern",
|
||||||
"change_exchange_provider": "Swap -Anbieter ändern",
|
"change_exchange_provider": "Swap-Anbieter ändern",
|
||||||
"change_language": "Sprache ändern",
|
"change_language": "Sprache ändern",
|
||||||
"change_language_to": "Sprache zu ${language} ändern?",
|
"change_language_to": "Sprache zu ${language} ändern?",
|
||||||
"change_password": "Passwort ändern",
|
"change_password": "Passwort ändern",
|
||||||
|
@ -131,7 +131,7 @@
|
||||||
"choose_one": "Wähle ein",
|
"choose_one": "Wähle ein",
|
||||||
"choose_relay": "Bitte wählen Sie ein zu verwendendes Relais aus",
|
"choose_relay": "Bitte wählen Sie ein zu verwendendes Relais aus",
|
||||||
"choose_wallet_currency": "Bitte wählen Sie die Währung der Wallet:",
|
"choose_wallet_currency": "Bitte wählen Sie die Währung der Wallet:",
|
||||||
"choose_wallet_group": "Wählen Sie Brieftaschengruppe",
|
"choose_wallet_group": "Wählen Sie Walletgruppe",
|
||||||
"clear": "Zurücksetzen",
|
"clear": "Zurücksetzen",
|
||||||
"clearnet_link": "Clearnet-Link",
|
"clearnet_link": "Clearnet-Link",
|
||||||
"close": "Schließen",
|
"close": "Schließen",
|
||||||
|
@ -179,7 +179,7 @@
|
||||||
"create_invoice": "Rechnung erstellen",
|
"create_invoice": "Rechnung erstellen",
|
||||||
"create_new": "Neue Wallet erstellen",
|
"create_new": "Neue Wallet erstellen",
|
||||||
"create_new_account": "Neues Konto erstellen",
|
"create_new_account": "Neues Konto erstellen",
|
||||||
"create_new_seed": "Neue Samen erstellen",
|
"create_new_seed": "Neue Seed erstellen",
|
||||||
"creating_new_wallet": "Neue Wallet erstellen",
|
"creating_new_wallet": "Neue Wallet erstellen",
|
||||||
"creating_new_wallet_error": "Fehler: ${description}",
|
"creating_new_wallet_error": "Fehler: ${description}",
|
||||||
"creation_date": "Erstellungsdatum",
|
"creation_date": "Erstellungsdatum",
|
||||||
|
@ -189,9 +189,9 @@
|
||||||
"custom_value": "Benutzerdefinierten Wert",
|
"custom_value": "Benutzerdefinierten Wert",
|
||||||
"dark_theme": "Dunkel",
|
"dark_theme": "Dunkel",
|
||||||
"debit_card": "Debitkarte",
|
"debit_card": "Debitkarte",
|
||||||
"debit_card_terms": "Die Speicherung und Nutzung Ihrer Zahlungskartennummer (und Ihrer Zahlungskartennummer entsprechenden Anmeldeinformationen) in dieser digitalen Geldbörse unterliegt den Allgemeinen Geschäftsbedingungen des geltenden Karteninhabervertrags mit dem Zahlungskartenaussteller, gültig ab von Zeit zu Zeit.",
|
"debit_card_terms": "Die Speicherung und Nutzung Ihrer Zahlungskartennummer (und Ihrer Zahlungskartennummer entsprechenden Anmeldeinformationen) in dieser digitalen Wallet unterliegt den Allgemeinen Geschäftsbedingungen des geltenden Karteninhabervertrags mit dem Zahlungskartenaussteller, gültig ab von Zeit zu Zeit.",
|
||||||
"decimal_places_error": "Zu viele Nachkommastellen",
|
"decimal_places_error": "Zu viele Nachkommastellen",
|
||||||
"decimals_cannot_be_zero": "Token -Dezimalzahl kann nicht Null sein.",
|
"decimals_cannot_be_zero": "Token-Dezimalzahl kann nicht Null sein.",
|
||||||
"default_buy_provider": "Standard-Kaufanbieter",
|
"default_buy_provider": "Standard-Kaufanbieter",
|
||||||
"default_sell_provider": "Standard-Verkaufsanbieter",
|
"default_sell_provider": "Standard-Verkaufsanbieter",
|
||||||
"delete": "Löschen",
|
"delete": "Löschen",
|
||||||
|
@ -236,7 +236,7 @@
|
||||||
"electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin",
|
"electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin",
|
||||||
"email_address": "E-Mail-Adresse",
|
"email_address": "E-Mail-Adresse",
|
||||||
"enable": "Aktivieren",
|
"enable": "Aktivieren",
|
||||||
"enable_mempool_api": "Mempool -API für genaue Gebühren und Daten",
|
"enable_mempool_api": "Mempool-API für genaue Gebühren und Daten",
|
||||||
"enable_replace_by_fee": "Aktivieren Sie Ersatz für Fee",
|
"enable_replace_by_fee": "Aktivieren Sie Ersatz für Fee",
|
||||||
"enable_silent_payments_scanning": "Scannen Sie stille Zahlungen, bis die Spitze erreicht ist",
|
"enable_silent_payments_scanning": "Scannen Sie stille Zahlungen, bis die Spitze erreicht ist",
|
||||||
"enabled": "Ermöglicht",
|
"enabled": "Ermöglicht",
|
||||||
|
@ -245,7 +245,7 @@
|
||||||
"enter_code": "Code eingeben",
|
"enter_code": "Code eingeben",
|
||||||
"enter_seed_phrase": "Geben Sie Ihre Seed-Phrase ein",
|
"enter_seed_phrase": "Geben Sie Ihre Seed-Phrase ein",
|
||||||
"enter_totp_code": "Bitte geben Sie den TOTP-Code ein.",
|
"enter_totp_code": "Bitte geben Sie den TOTP-Code ein.",
|
||||||
"enter_wallet_password": "Geben Sie das Brieftaschenkennwort ein",
|
"enter_wallet_password": "Geben Sie das Walletkennwort ein",
|
||||||
"enter_your_note": "Geben Sie Ihre Bemerkung ein…",
|
"enter_your_note": "Geben Sie Ihre Bemerkung ein…",
|
||||||
"enter_your_pin": "PIN eingeben",
|
"enter_your_pin": "PIN eingeben",
|
||||||
"enter_your_pin_again": "Geben Sie Ihre PIN erneut ein",
|
"enter_your_pin_again": "Geben Sie Ihre PIN erneut ein",
|
||||||
|
@ -282,7 +282,7 @@
|
||||||
"event": "Ereignis",
|
"event": "Ereignis",
|
||||||
"events": "Veranstaltungen",
|
"events": "Veranstaltungen",
|
||||||
"exchange": "Tauschen",
|
"exchange": "Tauschen",
|
||||||
"exchange_incorrect_current_wallet_for_xmr": "Wenn Sie XMR aus Ihrer Cake -Wallet Monero -Balance austauschen möchten, wechseln Sie zuerst zu Ihrer Monero -Brieftasche.",
|
"exchange_incorrect_current_wallet_for_xmr": "Wenn Sie XMR aus Ihrer CakeWallet Monero-Balance tauschen möchten, wechseln Sie zuerst zu Ihrer Monero-Wallet.",
|
||||||
"exchange_new_template": "Neue Vorlage",
|
"exchange_new_template": "Neue Vorlage",
|
||||||
"exchange_provider_unsupported": "${providerName} wird nicht mehr unterstützt!",
|
"exchange_provider_unsupported": "${providerName} wird nicht mehr unterstützt!",
|
||||||
"exchange_result_confirm": "Durch Drücken von \"Bestätigen\" wird ${fetchingLabel} ${from} von Ihrer Wallet namens ${walletName} an die unten angegebene Adresse gesendet. Alternativ können Sie von einer externen Wallet an die unten angegebene Adresse / QR-Code senden.\n\nBitte bestätigen Sie, um fortzufahren, oder gehen Sie zurück, um die Beträge zu ändern.",
|
"exchange_result_confirm": "Durch Drücken von \"Bestätigen\" wird ${fetchingLabel} ${from} von Ihrer Wallet namens ${walletName} an die unten angegebene Adresse gesendet. Alternativ können Sie von einer externen Wallet an die unten angegebene Adresse / QR-Code senden.\n\nBitte bestätigen Sie, um fortzufahren, oder gehen Sie zurück, um die Beträge zu ändern.",
|
||||||
|
@ -309,7 +309,7 @@
|
||||||
"fill_code": "Geben Sie den Bestätigungscode ein, den Sie per E-Mail erhalten haben",
|
"fill_code": "Geben Sie den Bestätigungscode ein, den Sie per E-Mail erhalten haben",
|
||||||
"filter_by": "Filtern nach",
|
"filter_by": "Filtern nach",
|
||||||
"first_wallet_text": "Eine großartige Wallet für Monero, Bitcoin, Ethereum, Litecoin, und Haven",
|
"first_wallet_text": "Eine großartige Wallet für Monero, Bitcoin, Ethereum, Litecoin, und Haven",
|
||||||
"fixed_pair_not_supported": "Dieses feste Paar wird nicht von den ausgewählten Swap -Diensten unterstützt",
|
"fixed_pair_not_supported": "Dieses feste Paar wird nicht von den ausgewählten Swap-Diensten unterstützt",
|
||||||
"fixed_rate": "Feste Rate",
|
"fixed_rate": "Feste Rate",
|
||||||
"fixed_rate_alert": "Sie können den Empfangsbetrag eingeben, wenn der Festratenmodus aktiviert ist. Möchten Sie in den Festratenmodus wechseln?",
|
"fixed_rate_alert": "Sie können den Empfangsbetrag eingeben, wenn der Festratenmodus aktiviert ist. Möchten Sie in den Festratenmodus wechseln?",
|
||||||
"forgot_password": "Passwort vergessen",
|
"forgot_password": "Passwort vergessen",
|
||||||
|
@ -349,9 +349,9 @@
|
||||||
"incoming": "Eingehend",
|
"incoming": "Eingehend",
|
||||||
"incorrect_seed": "Der eingegebene Text ist ungültig.",
|
"incorrect_seed": "Der eingegebene Text ist ungültig.",
|
||||||
"inputs": "Eingänge",
|
"inputs": "Eingänge",
|
||||||
"insufficient_lamport_for_tx": "Sie haben nicht genug SOL, um die Transaktion und ihre Transaktionsgebühr abzudecken. Bitte fügen Sie Ihrer Brieftasche mehr Sol hinzu oder reduzieren Sie die SO -Menge, die Sie senden.",
|
"insufficient_lamport_for_tx": "Sie haben nicht genug SOL, um die Transaktion und ihre Transaktionsgebühr abzudecken. Bitte fügen Sie Ihrer Wallet mehr Sol hinzu oder reduzieren Sie die SOL-Menge, die Sie senden.",
|
||||||
"insufficient_lamports": "Sie haben nicht genug SOL, um die Transaktion und ihre Transaktionsgebühr abzudecken. Sie brauchen mindestens ${solValueNeeded} Sol. Bitte fügen Sie mehr Sol zu Ihrer Wallet hinzu oder reduzieren Sie den von Ihnen gesendeten Sol -Betrag",
|
"insufficient_lamports": "Sie haben nicht genug SOL, um die Transaktion und ihre Transaktionsgebühr abzudecken. Sie brauchen mindestens ${solValueNeeded} Sol. Bitte fügen Sie mehr Sol zu Ihrer Wallet hinzu oder reduzieren Sie den von Ihnen gesendeten Sol-Betrag",
|
||||||
"insufficientFundsForRentError": "Sie haben nicht genug SOL, um die Transaktionsgebühr und die Miete für das Konto zu decken. Bitte fügen Sie mehr Sol zu Ihrer Brieftasche hinzu oder reduzieren Sie den von Ihnen gesendeten Sol -Betrag",
|
"insufficientFundsForRentError": "Sie haben nicht genug SOL, um die Transaktionsgebühr und die Miete für das Konto zu decken. Bitte fügen Sie mehr Sol zu Ihrer Wallet hinzu oder reduzieren Sie den von Ihnen gesendeten Sol-Betrag",
|
||||||
"introducing_cake_pay": "Einführung von Cake Pay!",
|
"introducing_cake_pay": "Einführung von Cake Pay!",
|
||||||
"invalid_input": "Ungültige Eingabe",
|
"invalid_input": "Ungültige Eingabe",
|
||||||
"invalid_password": "Ungültiges Passwort",
|
"invalid_password": "Ungültiges Passwort",
|
||||||
|
@ -365,20 +365,20 @@
|
||||||
"ledger_error_wrong_app": "Bitte stellen Sie sicher, dass Sie die richtige App auf Ihrem Ledger geöffnet haben",
|
"ledger_error_wrong_app": "Bitte stellen Sie sicher, dass Sie die richtige App auf Ihrem Ledger geöffnet haben",
|
||||||
"ledger_please_enable_bluetooth": "Bitte aktivieren Sie Bluetooth um sich mit Ihren Ledger zu verbinden.",
|
"ledger_please_enable_bluetooth": "Bitte aktivieren Sie Bluetooth um sich mit Ihren Ledger zu verbinden.",
|
||||||
"light_theme": "Hell",
|
"light_theme": "Hell",
|
||||||
"litecoin_enable_mweb_sync": "Aktivieren Sie das MWEB -Scannen",
|
"litecoin_enable_mweb_sync": "Aktivieren Sie das MWEB-Scannen",
|
||||||
"litecoin_mweb": "MWeb",
|
"litecoin_mweb": "MWeb",
|
||||||
"litecoin_mweb_always_scan": "Setzen Sie MWeb immer scannen",
|
"litecoin_mweb_always_scan": "Setzen Sie MWeb immer scannen",
|
||||||
"litecoin_mweb_description": "MWEB ist ein neues Protokoll, das schnellere, billigere und privatere Transaktionen zu Litecoin bringt",
|
"litecoin_mweb_description": "MWWB ist ein neues Protokoll, das schnellere, billigere und privatere Transaktionen zu Litecoin bringt",
|
||||||
"litecoin_mweb_dismiss": "Zurückweisen",
|
"litecoin_mweb_dismiss": "Zurückweisen",
|
||||||
"litecoin_mweb_display_card": "MWEB -Karte anzeigen",
|
"litecoin_mweb_display_card": "MWEB-Karte anzeigen",
|
||||||
"litecoin_mweb_enable_later": "Sie können MWEB unter Anzeigeeinstellungen erneut aktivieren.",
|
"litecoin_mweb_enable_later": "Sie können MWEB unter Anzeigeeinstellungen erneut aktivieren.",
|
||||||
"litecoin_mweb_pegin": "Peg in",
|
"litecoin_mweb_pegin": "Peg in",
|
||||||
"litecoin_mweb_pegout": "Abstecken",
|
"litecoin_mweb_pegout": "Abstecken",
|
||||||
"litecoin_mweb_scanning": "MWEB Scanning",
|
"litecoin_mweb_scanning": "MWEB Scanning",
|
||||||
"litecoin_mweb_settings": "MWEB -Einstellungen",
|
"litecoin_mweb_settings": "MWEB-Einstellungen",
|
||||||
"litecoin_mweb_warning": "Durch die Verwendung von MWEB wird zunächst ~ 600 MB Daten heruntergeladen und kann je nach Netzwerkgeschwindigkeit bis zu 30 Minuten dauern. Diese ersten Daten werden nur einmal heruntergeladen und für alle Litecoin -Brieftaschen verfügbar",
|
"litecoin_mweb_warning": "Durch die Verwendung von MWEB wird zunächst ~ 600 MB Daten heruntergeladen und kann je nach Netzwerkgeschwindigkeit bis zu 30 Minuten dauern. Diese ersten Daten werden nur einmal heruntergeladen und für alle Litecoin-Wallets verfügbar",
|
||||||
"litecoin_what_is_mweb": "Was ist MWeb?",
|
"litecoin_what_is_mweb": "Was ist MWeb?",
|
||||||
"live_fee_rates": "Live -Gebührenpreise über API",
|
"live_fee_rates": "Live-Gebührenpreise über API",
|
||||||
"load_more": "Mehr laden",
|
"load_more": "Mehr laden",
|
||||||
"loading_your_wallet": "Wallet wird geladen",
|
"loading_your_wallet": "Wallet wird geladen",
|
||||||
"login": "Einloggen",
|
"login": "Einloggen",
|
||||||
|
@ -533,8 +533,8 @@
|
||||||
"rename": "Umbenennen",
|
"rename": "Umbenennen",
|
||||||
"rep_warning": "Repräsentative Warnung",
|
"rep_warning": "Repräsentative Warnung",
|
||||||
"rep_warning_sub": "Ihr Vertreter scheint nicht gut zu sein. Tippen Sie hier, um eine neue auszuwählen",
|
"rep_warning_sub": "Ihr Vertreter scheint nicht gut zu sein. Tippen Sie hier, um eine neue auszuwählen",
|
||||||
"repeat_wallet_password": "Wiederholen Sie das Brieftaschenkennwort",
|
"repeat_wallet_password": "Wiederholen Sie das Walletkennwort",
|
||||||
"repeated_password_is_incorrect": "Wiederholtes Passwort ist falsch. Bitte wiederholen Sie das Brieftaschenkennwort erneut.",
|
"repeated_password_is_incorrect": "Wiederholtes Passwort ist falsch. Bitte wiederholen Sie das Walletkennwort erneut.",
|
||||||
"require_for_adding_contacts": "Erforderlich zum Hinzufügen von Kontakten",
|
"require_for_adding_contacts": "Erforderlich zum Hinzufügen von Kontakten",
|
||||||
"require_for_all_security_and_backup_settings": "Für alle Sicherheits- und Sicherungseinstellungen erforderlich",
|
"require_for_all_security_and_backup_settings": "Für alle Sicherheits- und Sicherungseinstellungen erforderlich",
|
||||||
"require_for_assessing_wallet": "Für den Zugriff auf die Wallet erforderlich",
|
"require_for_assessing_wallet": "Für den Zugriff auf die Wallet erforderlich",
|
||||||
|
@ -576,7 +576,7 @@
|
||||||
"restore_wallet": "Wallet wiederherstellen",
|
"restore_wallet": "Wallet wiederherstellen",
|
||||||
"restore_wallet_name": "Walletname",
|
"restore_wallet_name": "Walletname",
|
||||||
"restore_wallet_restore_description": "Beschreibung zur Wallet-Wiederherstellung",
|
"restore_wallet_restore_description": "Beschreibung zur Wallet-Wiederherstellung",
|
||||||
"robinhood_option_description": "Kaufen und übertragen Sie sofort mit Ihrem Debitkarten-, Bankkonto- oder Robinhood -Guthaben. Nur USA.",
|
"robinhood_option_description": "Kaufen und übertragen Sie sofort mit Ihrem Debitkarten-, Bankkonto- oder Robinhood-Guthaben. Nur USA.",
|
||||||
"router_no_route": "Keine Route definiert für ${name}",
|
"router_no_route": "Keine Route definiert für ${name}",
|
||||||
"save": "Speichern",
|
"save": "Speichern",
|
||||||
"save_backup_password": "Bitte stellen Sie sicher, dass Sie Ihr Sicherungskennwort gespeichert haben. Ohne dieses können Sie Ihre Sicherungsdateien nicht importieren.",
|
"save_backup_password": "Bitte stellen Sie sicher, dass Sie Ihr Sicherungskennwort gespeichert haben. Ohne dieses können Sie Ihre Sicherungsdateien nicht importieren.",
|
||||||
|
@ -622,8 +622,8 @@
|
||||||
"seed_share": "Seed teilen",
|
"seed_share": "Seed teilen",
|
||||||
"seed_title": "Seed",
|
"seed_title": "Seed",
|
||||||
"seedtype": "Seedtyp",
|
"seedtype": "Seedtyp",
|
||||||
"seedtype_alert_content": "Das Teilen von Samen mit anderen Brieftaschen ist nur mit bip39 Seedype möglich.",
|
"seedtype_alert_content": "Das Teilen von Seeds mit anderen Wallet ist nur mit bip39 Seedype möglich.",
|
||||||
"seedtype_alert_title": "Seedype -Alarm",
|
"seedtype_alert_title": "Seedype-Alarm",
|
||||||
"seedtype_legacy": "Veraltet (25 Wörter)",
|
"seedtype_legacy": "Veraltet (25 Wörter)",
|
||||||
"seedtype_polyseed": "Polyseed (16 Wörter)",
|
"seedtype_polyseed": "Polyseed (16 Wörter)",
|
||||||
"seedtype_wownero": "WOWNO (14 Wörter)",
|
"seedtype_wownero": "WOWNO (14 Wörter)",
|
||||||
|
@ -691,7 +691,7 @@
|
||||||
"setup_your_debit_card": "Richten Sie Ihre Debitkarte ein",
|
"setup_your_debit_card": "Richten Sie Ihre Debitkarte ein",
|
||||||
"share": "Teilen",
|
"share": "Teilen",
|
||||||
"share_address": "Adresse teilen ",
|
"share_address": "Adresse teilen ",
|
||||||
"shared_seed_wallet_groups": "Gemeinsame Samenbrieftaschengruppen",
|
"shared_seed_wallet_groups": "Gemeinsame Walletsseed Gruppen",
|
||||||
"show_details": "Details anzeigen",
|
"show_details": "Details anzeigen",
|
||||||
"show_keys": "Seed/Schlüssel anzeigen",
|
"show_keys": "Seed/Schlüssel anzeigen",
|
||||||
"show_market_place": "Marktplatz anzeigen",
|
"show_market_place": "Marktplatz anzeigen",
|
||||||
|
@ -711,12 +711,12 @@
|
||||||
"silent_payments_disclaimer": "Neue Adressen sind keine neuen Identitäten. Es ist eine Wiederverwendung einer bestehenden Identität mit einem anderen Etikett.",
|
"silent_payments_disclaimer": "Neue Adressen sind keine neuen Identitäten. Es ist eine Wiederverwendung einer bestehenden Identität mit einem anderen Etikett.",
|
||||||
"silent_payments_display_card": "Zeigen Sie stille Zahlungskarte",
|
"silent_payments_display_card": "Zeigen Sie stille Zahlungskarte",
|
||||||
"silent_payments_scan_from_date": "Scan ab Datum",
|
"silent_payments_scan_from_date": "Scan ab Datum",
|
||||||
"silent_payments_scan_from_date_or_blockheight": "Bitte geben Sie die Blockhöhe ein, die Sie für eingehende stille Zahlungen scannen möchten, oder verwenden Sie stattdessen das Datum. Sie können wählen, ob die Brieftasche jeden Block scannt oder nur die angegebene Höhe überprüft.",
|
"silent_payments_scan_from_date_or_blockheight": "Bitte geben Sie die Blockhöhe ein, die Sie für eingehende stille Zahlungen scannen möchten, oder verwenden Sie stattdessen das Datum. Sie können wählen, ob die Wallet jeden Block scannt oder nur die angegebene Höhe überprüft.",
|
||||||
"silent_payments_scan_from_height": "Scan aus der Blockhöhe scannen",
|
"silent_payments_scan_from_height": "Scan aus der Blockhöhe scannen",
|
||||||
"silent_payments_scanned_tip": "Gescannt zum Trinkgeld! (${tip})",
|
"silent_payments_scanned_tip": "Gescannt zum Trinkgeld! (${tip})",
|
||||||
"silent_payments_scanning": "Stille Zahlungen scannen",
|
"silent_payments_scanning": "Stille Zahlungen scannen",
|
||||||
"silent_payments_settings": "Einstellungen für stille Zahlungen",
|
"silent_payments_settings": "Einstellungen für stille Zahlungen",
|
||||||
"single_seed_wallets_group": "Einzelne Samenbriefen",
|
"single_seed_wallets_group": "Einzelne Wallets",
|
||||||
"slidable": "Verschiebbar",
|
"slidable": "Verschiebbar",
|
||||||
"sort_by": "Sortiere nach",
|
"sort_by": "Sortiere nach",
|
||||||
"spend_key_private": "Spend Key (geheim)",
|
"spend_key_private": "Spend Key (geheim)",
|
||||||
|
@ -755,11 +755,11 @@
|
||||||
"syncing_wallet_alert_title": "Ihr Wallet wird synchronisiert",
|
"syncing_wallet_alert_title": "Ihr Wallet wird synchronisiert",
|
||||||
"template": "Vorlage",
|
"template": "Vorlage",
|
||||||
"template_name": "Vorlagenname",
|
"template_name": "Vorlagenname",
|
||||||
"testnet_coins_no_value": "Testnet -Münzen haben keinen Wert",
|
"testnet_coins_no_value": "Testnet-Münzen haben keinen Wert",
|
||||||
"third_intro_content": "Yats leben auch außerhalb von Cake Wallet. Jede Wallet-Adresse auf der Welt kann durch ein Yat ersetzt werden!",
|
"third_intro_content": "Yats leben auch außerhalb von Cake Wallet. Jede Wallet-Adresse auf der Welt kann durch ein Yat ersetzt werden!",
|
||||||
"third_intro_title": "Yat spielt gut mit anderen",
|
"third_intro_title": "Yat spielt gut mit anderen",
|
||||||
"thorchain_contract_address_not_supported": "Thorchain unterstützt das Senden an eine Vertragsadresse nicht",
|
"thorchain_contract_address_not_supported": "Thorchain unterstützt das Senden an eine Vertragsadresse nicht",
|
||||||
"thorchain_taproot_address_not_supported": "Der Thorchain -Anbieter unterstützt keine Taproot -Adressen. Bitte ändern Sie die Adresse oder wählen Sie einen anderen Anbieter aus.",
|
"thorchain_taproot_address_not_supported": "Der Thorchain-Anbieter unterstützt keine Taproot-Adressen. Bitte ändern Sie die Adresse oder wählen Sie einen anderen Anbieter aus.",
|
||||||
"time": "${minutes}m ${seconds}s",
|
"time": "${minutes}m ${seconds}s",
|
||||||
"tip": "Hinweis:",
|
"tip": "Hinweis:",
|
||||||
"today": "Heute",
|
"today": "Heute",
|
||||||
|
@ -879,12 +879,12 @@
|
||||||
"voting_weight": "Stimmgewicht",
|
"voting_weight": "Stimmgewicht",
|
||||||
"waitFewSecondForTxUpdate": "Bitte warten Sie einige Sekunden, bis die Transaktion im Transaktionsverlauf angezeigt wird",
|
"waitFewSecondForTxUpdate": "Bitte warten Sie einige Sekunden, bis die Transaktion im Transaktionsverlauf angezeigt wird",
|
||||||
"waiting_payment_confirmation": "Warte auf Zahlungsbestätigung",
|
"waiting_payment_confirmation": "Warte auf Zahlungsbestätigung",
|
||||||
"wallet_group": "Brieftaschengruppe",
|
"wallet_group": "Walletgruppe",
|
||||||
"wallet_group_description_four": "eine Brieftasche mit einem völlig neuen Samen schaffen.",
|
"wallet_group_description_four": "eine Wallet mit einem völlig neuen Seed schaffen.",
|
||||||
"wallet_group_description_one": "In Kuchenbrieftasche können Sie eine erstellen",
|
"wallet_group_description_one": "In CakeWallet können Sie eine erstellen",
|
||||||
"wallet_group_description_three": "Sehen Sie den Bildschirm zur verfügbaren Brieftaschen und/oder Brieftaschengruppen. Oder wählen",
|
"wallet_group_description_three": "Sehen Sie den Bildschirm zur verfügbaren Wallet und/oder Walletgruppen. Oder wählen",
|
||||||
"wallet_group_description_two": "Durch die Auswahl einer vorhandenen Brieftasche, mit der ein Samen geteilt werden kann. Jede Brieftaschengruppe kann eine einzelne Brieftasche jedes Währungstyps enthalten. \n\n Sie können auswählen",
|
"wallet_group_description_two": "Durch die Auswahl einer vorhandenen Wallet, mit der ein Seed geteilt werden kann. Jede Walletgruppe kann eine einzelne Wallet jedes Währungstyps enthalten. \n\n Sie können auswählen",
|
||||||
"wallet_group_empty_state_text_one": "Sieht so aus, als hätten Sie keine kompatiblen Brieftaschengruppen !\n\n TAP",
|
"wallet_group_empty_state_text_one": "Sieht so aus, als hätten Sie keine kompatiblen Walletgruppen !\n\n TAP",
|
||||||
"wallet_group_empty_state_text_two": "unten, um einen neuen zu machen.",
|
"wallet_group_empty_state_text_two": "unten, um einen neuen zu machen.",
|
||||||
"wallet_keys": "Wallet-Seed/-Schlüssel",
|
"wallet_keys": "Wallet-Seed/-Schlüssel",
|
||||||
"wallet_list_create_new_wallet": "Neue Wallet erstellen",
|
"wallet_list_create_new_wallet": "Neue Wallet erstellen",
|
||||||
|
@ -901,7 +901,7 @@
|
||||||
"wallet_menu": "Wallet-Menü",
|
"wallet_menu": "Wallet-Menü",
|
||||||
"wallet_name": "Walletname",
|
"wallet_name": "Walletname",
|
||||||
"wallet_name_exists": "Wallet mit diesem Namen existiert bereits",
|
"wallet_name_exists": "Wallet mit diesem Namen existiert bereits",
|
||||||
"wallet_password_is_empty": "Brieftaschenkennwort ist leer. Brieftaschenkennwort sollte nicht leer sein",
|
"wallet_password_is_empty": "Walletkennwort ist leer. Walletkennwort sollte nicht leer sein",
|
||||||
"wallet_recovery_height": "Erstellungshöhe",
|
"wallet_recovery_height": "Erstellungshöhe",
|
||||||
"wallet_restoration_store_incorrect_seed_length": "Falsche Seed-Länge",
|
"wallet_restoration_store_incorrect_seed_length": "Falsche Seed-Länge",
|
||||||
"wallet_seed": "Wallet-Seed",
|
"wallet_seed": "Wallet-Seed",
|
||||||
|
@ -941,4 +941,4 @@
|
||||||
"you_will_get": "Konvertieren zu",
|
"you_will_get": "Konvertieren zu",
|
||||||
"you_will_send": "Konvertieren von",
|
"you_will_send": "Konvertieren von",
|
||||||
"yy": "YY"
|
"yy": "YY"
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
"billing_address_info": "Si se le solicita una dirección de facturación, proporcione su dirección de envío",
|
"billing_address_info": "Si se le solicita una dirección de facturación, proporcione su dirección de envío",
|
||||||
"biometric_auth_reason": "Escanee su huella digital para autenticar",
|
"biometric_auth_reason": "Escanee su huella digital para autenticar",
|
||||||
"bitcoin_dark_theme": "Tema oscuro de Bitcoin",
|
"bitcoin_dark_theme": "Tema oscuro de Bitcoin",
|
||||||
"bitcoin_light_theme": "Tema de la luz de Bitcoin",
|
"bitcoin_light_theme": "Tema claro de Bitcoin",
|
||||||
"bitcoin_payments_require_1_confirmation": "Los pagos de Bitcoin requieren 1 confirmación, que puede demorar 20 minutos o más. ¡Gracias por su paciencia! Se le enviará un correo electrónico cuando se confirme el pago.",
|
"bitcoin_payments_require_1_confirmation": "Los pagos de Bitcoin requieren 1 confirmación, que puede demorar 20 minutos o más. ¡Gracias por su paciencia! Se le enviará un correo electrónico cuando se confirme el pago.",
|
||||||
"block_remaining": "1 bloqueo restante",
|
"block_remaining": "1 bloqueo restante",
|
||||||
"Blocks_remaining": "${status} Bloques restantes",
|
"Blocks_remaining": "${status} Bloques restantes",
|
||||||
|
@ -93,7 +93,7 @@
|
||||||
"buy_with": "Compra con",
|
"buy_with": "Compra con",
|
||||||
"by_cake_pay": "por Cake Pay",
|
"by_cake_pay": "por Cake Pay",
|
||||||
"cake_2fa_preset": "Pastel 2FA preestablecido",
|
"cake_2fa_preset": "Pastel 2FA preestablecido",
|
||||||
"cake_dark_theme": "Tema oscuro del pastel",
|
"cake_dark_theme": "Tema oscuro",
|
||||||
"cake_pay_account_note": "Regístrese con solo una dirección de correo electrónico para ver y comprar tarjetas. ¡Algunas incluso están disponibles con descuento!",
|
"cake_pay_account_note": "Regístrese con solo una dirección de correo electrónico para ver y comprar tarjetas. ¡Algunas incluso están disponibles con descuento!",
|
||||||
"cake_pay_learn_more": "¡Compre y canjee tarjetas de regalo al instante en la aplicación!\nDeslice el dedo de izquierda a derecha para obtener más información.",
|
"cake_pay_learn_more": "¡Compre y canjee tarjetas de regalo al instante en la aplicación!\nDeslice el dedo de izquierda a derecha para obtener más información.",
|
||||||
"cake_pay_save_order": "La tarjeta debe enviarse a su correo electrónico dentro de 1 día hábil \n Guardar su ID de pedido:",
|
"cake_pay_save_order": "La tarjeta debe enviarse a su correo electrónico dentro de 1 día hábil \n Guardar su ID de pedido:",
|
||||||
|
@ -144,9 +144,9 @@
|
||||||
"confirm_delete_wallet": "Esta acción eliminará esta billetera. ¿Desea continuar?",
|
"confirm_delete_wallet": "Esta acción eliminará esta billetera. ¿Desea continuar?",
|
||||||
"confirm_fee_deduction": "Confirmar la deducción de la tarifa",
|
"confirm_fee_deduction": "Confirmar la deducción de la tarifa",
|
||||||
"confirm_fee_deduction_content": "¿Acepta deducir la tarifa de la producción?",
|
"confirm_fee_deduction_content": "¿Acepta deducir la tarifa de la producción?",
|
||||||
"confirm_passphrase": "Confirmar la frase de pases",
|
"confirm_passphrase": "Confirmar la contraseña",
|
||||||
"confirm_sending": "Confirmar envío",
|
"confirm_sending": "Confirmar envío",
|
||||||
"confirm_silent_payments_switch_node": "Su nodo actual no admite pagos silenciosos \\ ncake billet cambiará a un nodo compatible, solo para escanear",
|
"confirm_silent_payments_switch_node": "Su nodo actual no admite pagos silenciosos \\ nCake cambiará a un nodo compatible, solo para escanear",
|
||||||
"confirmations": "Confirmaciones",
|
"confirmations": "Confirmaciones",
|
||||||
"confirmed": "Saldo confirmado",
|
"confirmed": "Saldo confirmado",
|
||||||
"confirmed_tx": "Confirmado",
|
"confirmed_tx": "Confirmado",
|
||||||
|
@ -281,7 +281,7 @@
|
||||||
"etherscan_history": "historia de etherscan",
|
"etherscan_history": "historia de etherscan",
|
||||||
"event": "Evento",
|
"event": "Evento",
|
||||||
"events": "Eventos",
|
"events": "Eventos",
|
||||||
"exchange": "Intercambio",
|
"exchange": "Intercambiar",
|
||||||
"exchange_incorrect_current_wallet_for_xmr": "Si desea intercambiar XMR desde su billetera de pastel Monero Balance, primero cambie a su billetera Monero.",
|
"exchange_incorrect_current_wallet_for_xmr": "Si desea intercambiar XMR desde su billetera de pastel Monero Balance, primero cambie a su billetera Monero.",
|
||||||
"exchange_new_template": "Nueva plantilla",
|
"exchange_new_template": "Nueva plantilla",
|
||||||
"exchange_provider_unsupported": "¡${providerName} ya no es compatible!",
|
"exchange_provider_unsupported": "¡${providerName} ya no es compatible!",
|
||||||
|
@ -372,8 +372,8 @@
|
||||||
"litecoin_mweb_dismiss": "Despedir",
|
"litecoin_mweb_dismiss": "Despedir",
|
||||||
"litecoin_mweb_display_card": "Mostrar tarjeta MWEB",
|
"litecoin_mweb_display_card": "Mostrar tarjeta MWEB",
|
||||||
"litecoin_mweb_enable_later": "Puede elegir habilitar MWEB nuevamente en la configuración de visualización.",
|
"litecoin_mweb_enable_later": "Puede elegir habilitar MWEB nuevamente en la configuración de visualización.",
|
||||||
"litecoin_mweb_pegin": "Meter",
|
"litecoin_mweb_pegin": "Convertir",
|
||||||
"litecoin_mweb_pegout": "Estirar la pata",
|
"litecoin_mweb_pegout": "Recuperar",
|
||||||
"litecoin_mweb_scanning": "Escaneo mweb",
|
"litecoin_mweb_scanning": "Escaneo mweb",
|
||||||
"litecoin_mweb_settings": "Configuración de MWEB",
|
"litecoin_mweb_settings": "Configuración de MWEB",
|
||||||
"litecoin_mweb_warning": "El uso de MWEB inicialmente descargará ~ 600 MB de datos, y puede tomar hasta 30 minutos según la velocidad de la red. Estos datos iniciales solo se descargarán una vez y estarán disponibles para todas las billeteras de Litecoin",
|
"litecoin_mweb_warning": "El uso de MWEB inicialmente descargará ~ 600 MB de datos, y puede tomar hasta 30 minutos según la velocidad de la red. Estos datos iniciales solo se descargarán una vez y estarán disponibles para todas las billeteras de Litecoin",
|
||||||
|
@ -826,7 +826,7 @@
|
||||||
"transaction_priority_slow": "Lento",
|
"transaction_priority_slow": "Lento",
|
||||||
"transaction_sent": "Transacción enviada!",
|
"transaction_sent": "Transacción enviada!",
|
||||||
"transaction_sent_notice": "Si la pantalla no continúa después de 1 minuto, revisa un explorador de bloques y tu correo electrónico.",
|
"transaction_sent_notice": "Si la pantalla no continúa después de 1 minuto, revisa un explorador de bloques y tu correo electrónico.",
|
||||||
"transactions": "Actas",
|
"transactions": "Transacciones",
|
||||||
"transactions_by_date": "Transacciones por fecha",
|
"transactions_by_date": "Transacciones por fecha",
|
||||||
"trongrid_history": "Historia trongrid",
|
"trongrid_history": "Historia trongrid",
|
||||||
"trusted": "de confianza",
|
"trusted": "de confianza",
|
||||||
|
@ -939,4 +939,4 @@
|
||||||
"you_will_get": "Convertir a",
|
"you_will_get": "Convertir a",
|
||||||
"you_will_send": "Convertir de",
|
"you_will_send": "Convertir de",
|
||||||
"yy": "YY"
|
"yy": "YY"
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,8 @@ MONERO_COM_PACKAGE="com.monero.app"
|
||||||
MONERO_COM_SCHEME="monero.com"
|
MONERO_COM_SCHEME="monero.com"
|
||||||
|
|
||||||
CAKEWALLET_NAME="Cake Wallet"
|
CAKEWALLET_NAME="Cake Wallet"
|
||||||
CAKEWALLET_VERSION="4.20.0"
|
CAKEWALLET_VERSION="4.20.1"
|
||||||
CAKEWALLET_BUILD_NUMBER=232
|
CAKEWALLET_BUILD_NUMBER=233
|
||||||
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
|
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
|
||||||
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
|
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
|
||||||
CAKEWALLET_SCHEME="cakewallet"
|
CAKEWALLET_SCHEME="cakewallet"
|
||||||
|
|
|
@ -18,8 +18,8 @@ MONERO_COM_BUILD_NUMBER=101
|
||||||
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
|
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
|
||||||
|
|
||||||
CAKEWALLET_NAME="Cake Wallet"
|
CAKEWALLET_NAME="Cake Wallet"
|
||||||
CAKEWALLET_VERSION="4.20.0"
|
CAKEWALLET_VERSION="4.20.1"
|
||||||
CAKEWALLET_BUILD_NUMBER=276
|
CAKEWALLET_BUILD_NUMBER=277
|
||||||
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
|
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
|
||||||
|
|
||||||
HAVEN_NAME="Haven"
|
HAVEN_NAME="Haven"
|
||||||
|
|
|
@ -14,8 +14,8 @@ if [ -n "$1" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CAKEWALLET_NAME="Cake Wallet"
|
CAKEWALLET_NAME="Cake Wallet"
|
||||||
CAKEWALLET_VERSION="1.10.0"
|
CAKEWALLET_VERSION="1.10.1"
|
||||||
CAKEWALLET_BUILD_NUMBER=36
|
CAKEWALLET_BUILD_NUMBER=37
|
||||||
|
|
||||||
if ! [[ " ${TYPES[*]} " =~ " ${APP_LINUX_TYPE} " ]]; then
|
if ! [[ " ${TYPES[*]} " =~ " ${APP_LINUX_TYPE} " ]]; then
|
||||||
echo "Wrong app type."
|
echo "Wrong app type."
|
||||||
|
|
|
@ -21,8 +21,8 @@ MONERO_COM_BUILD_NUMBER=34
|
||||||
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
|
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
|
||||||
|
|
||||||
CAKEWALLET_NAME="Cake Wallet"
|
CAKEWALLET_NAME="Cake Wallet"
|
||||||
CAKEWALLET_VERSION="1.13.0"
|
CAKEWALLET_VERSION="1.13.1"
|
||||||
CAKEWALLET_BUILD_NUMBER=92
|
CAKEWALLET_BUILD_NUMBER=93
|
||||||
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
|
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
|
||||||
|
|
||||||
if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then
|
if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#define MyAppName "Cake Wallet"
|
#define MyAppName "Cake Wallet"
|
||||||
#define MyAppVersion "0.1.0"
|
#define MyAppVersion "0.1.1"
|
||||||
#define MyAppPublisher "Cake Labs LLC"
|
#define MyAppPublisher "Cake Labs LLC"
|
||||||
#define MyAppURL "https://cakewallet.com/"
|
#define MyAppURL "https://cakewallet.com/"
|
||||||
#define MyAppExeName "CakeWallet.exe"
|
#define MyAppExeName "CakeWallet.exe"
|
||||||
|
|
|
@ -97,7 +97,7 @@ import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:cw_core/get_height_by_date.dart';
|
import 'package:cw_core/get_height_by_date.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as ledger;
|
||||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
""";
|
""";
|
||||||
|
@ -121,6 +121,7 @@ import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
|
||||||
import 'package:cw_bitcoin/litecoin_wallet_service.dart';
|
import 'package:cw_bitcoin/litecoin_wallet_service.dart';
|
||||||
import 'package:cw_bitcoin/litecoin_wallet.dart';
|
import 'package:cw_bitcoin/litecoin_wallet.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_hardware_wallet_service.dart';
|
import 'package:cw_bitcoin/bitcoin_hardware_wallet_service.dart';
|
||||||
|
import 'package:cw_bitcoin/litecoin_hardware_wallet_service.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
""";
|
""";
|
||||||
const bitcoinCwPart = "part 'cw_bitcoin.dart';";
|
const bitcoinCwPart = "part 'cw_bitcoin.dart';";
|
||||||
|
@ -223,14 +224,15 @@ abstract class Bitcoin {
|
||||||
void deleteSilentPaymentAddress(Object wallet, String address);
|
void deleteSilentPaymentAddress(Object wallet, String address);
|
||||||
Future<void> updateFeeRates(Object wallet);
|
Future<void> updateFeeRates(Object wallet);
|
||||||
int getMaxCustomFeeRate(Object wallet);
|
int getMaxCustomFeeRate(Object wallet);
|
||||||
void setLedger(WalletBase wallet, Ledger ledger, LedgerDevice device);
|
void setLedgerConnection(WalletBase wallet, ledger.LedgerConnection connection);
|
||||||
Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM, {int index = 0, int limit = 5});
|
Future<List<HardwareAccountData>> getHardwareWalletBitcoinAccounts(LedgerViewModel ledgerVM, {int index = 0, int limit = 5});
|
||||||
dynamic getStatusRequest(Object wallet);
|
Future<List<HardwareAccountData>> getHardwareWalletLitecoinAccounts(LedgerViewModel ledgerVM, {int index = 0, int limit = 5});
|
||||||
List<Output> updateOutputs(PendingTransaction pendingTransaction, List<Output> outputs);
|
List<Output> updateOutputs(PendingTransaction pendingTransaction, List<Output> outputs);
|
||||||
bool txIsReceivedSilentPayment(TransactionInfo txInfo);
|
bool txIsReceivedSilentPayment(TransactionInfo txInfo);
|
||||||
bool txIsMweb(TransactionInfo txInfo);
|
bool txIsMweb(TransactionInfo txInfo);
|
||||||
Future<void> setMwebEnabled(Object wallet, bool enabled);
|
Future<void> setMwebEnabled(Object wallet, bool enabled);
|
||||||
bool getMwebEnabled(Object wallet);
|
bool getMwebEnabled(Object wallet);
|
||||||
|
dynamic getStatusRequest(Object wallet);
|
||||||
String? getUnusedMwebAddress(Object wallet);
|
String? getUnusedMwebAddress(Object wallet);
|
||||||
String? getUnusedSegwitAddress(Object wallet);
|
String? getUnusedSegwitAddress(Object wallet);
|
||||||
}
|
}
|
||||||
|
@ -820,7 +822,7 @@ import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_service.dart';
|
import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as ledger;
|
||||||
import 'package:web3dart/web3dart.dart';
|
import 'package:web3dart/web3dart.dart';
|
||||||
|
|
||||||
""";
|
""";
|
||||||
|
@ -886,7 +888,7 @@ abstract class Ethereum {
|
||||||
Web3Client? getWeb3Client(WalletBase wallet);
|
Web3Client? getWeb3Client(WalletBase wallet);
|
||||||
String getTokenAddress(CryptoCurrency asset);
|
String getTokenAddress(CryptoCurrency asset);
|
||||||
|
|
||||||
void setLedger(WalletBase wallet, Ledger ledger, LedgerDevice device);
|
void setLedgerConnection(WalletBase wallet, ledger.LedgerConnection connection);
|
||||||
Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM, {int index = 0, int limit = 5});
|
Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM, {int index = 0, int limit = 5});
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
@ -924,7 +926,7 @@ import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_service.dart';
|
import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as ledger;
|
||||||
import 'package:web3dart/web3dart.dart';
|
import 'package:web3dart/web3dart.dart';
|
||||||
|
|
||||||
""";
|
""";
|
||||||
|
@ -990,7 +992,7 @@ abstract class Polygon {
|
||||||
Web3Client? getWeb3Client(WalletBase wallet);
|
Web3Client? getWeb3Client(WalletBase wallet);
|
||||||
String getTokenAddress(CryptoCurrency asset);
|
String getTokenAddress(CryptoCurrency asset);
|
||||||
|
|
||||||
void setLedger(WalletBase wallet, Ledger ledger, LedgerDevice device);
|
void setLedgerConnection(WalletBase wallet, ledger.LedgerConnection connection);
|
||||||
Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM, {int index = 0, int limit = 5});
|
Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM, {int index = 0, int limit = 5});
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||||
#include <share_plus/share_plus_windows_plugin_c_api.h>
|
#include <share_plus/share_plus_windows_plugin_c_api.h>
|
||||||
|
#include <universal_ble/universal_ble_plugin_c_api.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
@ -24,6 +25,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||||
SharePlusWindowsPluginCApiRegisterWithRegistrar(
|
SharePlusWindowsPluginCApiRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
|
registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
|
||||||
|
UniversalBlePluginCApiRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("UniversalBlePluginCApi"));
|
||||||
UrlLauncherWindowsRegisterWithRegistrar(
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
flutter_secure_storage_windows
|
flutter_secure_storage_windows
|
||||||
permission_handler_windows
|
permission_handler_windows
|
||||||
share_plus
|
share_plus
|
||||||
|
universal_ble
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue