diff --git a/assets/text/Release_Notes.txt b/assets/text/Release_Notes.txt
index 2f5130bea..ac032e354 100644
--- a/assets/text/Release_Notes.txt
+++ b/assets/text/Release_Notes.txt
@@ -1,5 +1,3 @@
-Bitcoin transactions fixes and enhancements
-EVM wallets enhancements (Ethereum and Polygon)
-Improve wallet recovery and error tolerance
-Enhance Background sync for Monero wallets
-Bug fixes
\ No newline at end of file
+Support ALL Bitcoin address types (Legacy, Segwit (both variants), Taproot)
+Enhance Sending/Receiving flow for Bitcoin
+Improve fee calculations in Bitcoin
\ No newline at end of file
diff --git a/cw_bitcoin/lib/address_from_output.dart b/cw_bitcoin/lib/address_from_output.dart
index d06ffe402..73bc101c4 100644
--- a/cw_bitcoin/lib/address_from_output.dart
+++ b/cw_bitcoin/lib/address_from_output.dart
@@ -1,23 +1,23 @@
-import 'dart:typed_data';
-import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
-import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
+import 'package:bitcoin_base/bitcoin_base.dart';
 
-String addressFromOutput(Uint8List script, bitcoin.NetworkType networkType) {
+String addressFromOutputScript(Script script, BasedUtxoNetwork network) {
   try {
-    return bitcoin.P2PKH(
-        data: PaymentData(output: script),
-        network: networkType)
-      .data
-      .address!;
+    switch (script.getAddressType()) {
+      case P2pkhAddressType.p2pkh:
+        return P2pkhAddress.fromScriptPubkey(script: script).toAddress(network);
+      case P2shAddressType.p2pkInP2sh:
+        return P2shAddress.fromScriptPubkey(script: script).toAddress(network);
+      case SegwitAddresType.p2wpkh:
+        return P2wpkhAddress.fromScriptPubkey(script: script).toAddress(network);
+      case P2shAddressType.p2pkhInP2sh:
+        return P2shAddress.fromScriptPubkey(script: script).toAddress(network);
+      case SegwitAddresType.p2wsh:
+        return P2wshAddress.fromScriptPubkey(script: script).toAddress(network);
+      case SegwitAddresType.p2tr:
+        return P2trAddress.fromScriptPubkey(script: script).toAddress(network);
+      default:
+    }
   } catch (_) {}
 
-  try {
-    return bitcoin.P2WPKH(
-        data: PaymentData(output: script),
-        network: networkType)
-      .data
-      .address!;
-  } catch(_) {}
-
   return '';
-}
\ No newline at end of file
+}
diff --git a/cw_bitcoin/lib/address_to_output_script.dart b/cw_bitcoin/lib/address_to_output_script.dart
index 01c7b67a5..6ae50132b 100644
--- a/cw_bitcoin/lib/address_to_output_script.dart
+++ b/cw_bitcoin/lib/address_to_output_script.dart
@@ -1,27 +1,9 @@
 import 'dart:typed_data';
-import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
-import 'package:bs58check/bs58check.dart' as bs58check;
-import 'package:bitcoin_flutter/src/utils/constants/op.dart';
-import 'package:bitcoin_flutter/src/utils/script.dart' as bscript;
-import 'package:bitcoin_flutter/src/address.dart';
+import 'package:bitcoin_base/bitcoin_base.dart' as bitcoin;
 
-Uint8List p2shAddressToOutputScript(String address) {
-  final decodeBase58 = bs58check.decode(address);
-  final hash = decodeBase58.sublist(1);
-  return bscript.compile(<dynamic>[OPS['OP_HASH160'], hash, OPS['OP_EQUAL']]);
-}
-
-Uint8List addressToOutputScript(
-    String address, bitcoin.NetworkType networkType) {
+List<int> addressToOutputScript(String address, bitcoin.BasedUtxoNetwork network) {
   try {
-    // FIXME: improve validation for p2sh addresses
-    // 3 for bitcoin
-    // m for litecoin
-    if (address.startsWith('3') || address.toLowerCase().startsWith('m')) {
-      return p2shAddressToOutputScript(address);
-    }
-
-    return Address.addressToOutputScript(address, networkType);
+    return bitcoin.addressToOutputScript(address: address, network: network);
   } catch (err) {
     print(err);
     return Uint8List(0);
diff --git a/cw_bitcoin/lib/bitcoin_address_record.dart b/cw_bitcoin/lib/bitcoin_address_record.dart
index 676edb4a5..d8d908230 100644
--- a/cw_bitcoin/lib/bitcoin_address_record.dart
+++ b/cw_bitcoin/lib/bitcoin_address_record.dart
@@ -1,6 +1,9 @@
 import 'dart:convert';
 import 'package:bitbox/bitbox.dart' as bitbox;
 
+import 'package:bitcoin_base/bitcoin_base.dart';
+import 'package:cw_bitcoin/script_hash.dart' as sh;
+
 class BitcoinAddressRecord {
   BitcoinAddressRecord(
     this.address, {
@@ -10,23 +13,41 @@ class BitcoinAddressRecord {
     int balance = 0,
     String name = '',
     bool isUsed = false,
+    required this.type,
+    String? scriptHash,
+    required this.network,
   })  : _txCount = txCount,
         _balance = balance,
         _name = name,
-        _isUsed = isUsed;
+        _isUsed = isUsed,
+        scriptHash =
+            scriptHash ?? (network != null ? sh.scriptHash(address, network: network) : null);
 
-  factory BitcoinAddressRecord.fromJSON(String jsonSource) {
+  factory BitcoinAddressRecord.fromJSON(String jsonSource, BasedUtxoNetwork? network) {
     final decoded = json.decode(jsonSource) as Map;
 
-    return BitcoinAddressRecord(decoded['address'] as String,
-        index: decoded['index'] as int,
-        isHidden: decoded['isHidden'] as bool? ?? false,
-        isUsed: decoded['isUsed'] as bool? ?? false,
-        txCount: decoded['txCount'] as int? ?? 0,
-        name: decoded['name'] as String? ?? '',
-        balance: decoded['balance'] as int? ?? 0);
+    return BitcoinAddressRecord(
+      decoded['address'] as String,
+      index: decoded['index'] as int,
+      isHidden: decoded['isHidden'] as bool? ?? false,
+      isUsed: decoded['isUsed'] as bool? ?? false,
+      txCount: decoded['txCount'] as int? ?? 0,
+      name: decoded['name'] as String? ?? '',
+      balance: decoded['balance'] as int? ?? 0,
+      type: decoded['type'] != null && decoded['type'] != ''
+          ? BitcoinAddressType.values
+              .firstWhere((type) => type.toString() == decoded['type'] as String)
+          : SegwitAddresType.p2wpkh,
+      scriptHash: decoded['scriptHash'] as String?,
+      network: (decoded['network'] as String?) == null
+          ? network
+          : BasedUtxoNetwork.fromName(decoded['network'] as String),
+    );
   }
 
+  @override
+  bool operator ==(Object o) => o is BitcoinAddressRecord && address == o.address;
+
   final String address;
   bool isHidden;
   final int index;
@@ -34,6 +55,8 @@ class BitcoinAddressRecord {
   int _balance;
   String _name;
   bool _isUsed;
+  String? scriptHash;
+  BasedUtxoNetwork? network;
 
   int get txCount => _txCount;
 
@@ -50,21 +73,28 @@ class BitcoinAddressRecord {
   void setAsUsed() => _isUsed = true;
   void setNewName(String label) => _name = label;
 
-  @override
-  bool operator ==(Object o) => o is BitcoinAddressRecord && address == o.address;
-
   @override
   int get hashCode => address.hashCode;
 
   String get cashAddr => bitbox.Address.toCashAddress(address);
 
+  BitcoinAddressType type;
+
+  String updateScriptHash(BasedUtxoNetwork network) {
+    scriptHash = sh.scriptHash(address, network: network);
+    return scriptHash!;
+  }
+
   String toJSON() => json.encode({
         'address': address,
         'index': index,
         'isHidden': isHidden,
+        'isUsed': isUsed,
         'txCount': txCount,
         'name': name,
-        'isUsed': isUsed,
         'balance': balance,
+        'type': type.toString(),
+        'scriptHash': scriptHash,
+        'network': network?.value,
       });
 }
diff --git a/cw_bitcoin/lib/bitcoin_receive_page_option.dart b/cw_bitcoin/lib/bitcoin_receive_page_option.dart
new file mode 100644
index 000000000..2e246f532
--- /dev/null
+++ b/cw_bitcoin/lib/bitcoin_receive_page_option.dart
@@ -0,0 +1,42 @@
+import 'package:bitcoin_base/bitcoin_base.dart';
+import 'package:cw_core/receive_page_option.dart';
+
+class BitcoinReceivePageOption implements ReceivePageOption {
+  static const p2wpkh = BitcoinReceivePageOption._('Segwit (P2WPKH)');
+  static const p2sh = BitcoinReceivePageOption._('Segwit-Compatible (P2SH)');
+  static const p2tr = BitcoinReceivePageOption._('Taproot (P2TR)');
+  static const p2wsh = BitcoinReceivePageOption._('Segwit (P2WSH)');
+  static const p2pkh = BitcoinReceivePageOption._('Legacy (P2PKH)');
+
+  const BitcoinReceivePageOption._(this.value);
+
+  final String value;
+
+  String toString() {
+    return value;
+  }
+
+  static const all = [
+    BitcoinReceivePageOption.p2wpkh,
+    BitcoinReceivePageOption.p2sh,
+    BitcoinReceivePageOption.p2tr,
+    BitcoinReceivePageOption.p2wsh,
+    BitcoinReceivePageOption.p2pkh
+  ];
+
+  factory BitcoinReceivePageOption.fromType(BitcoinAddressType type) {
+    switch (type) {
+      case SegwitAddresType.p2tr:
+        return BitcoinReceivePageOption.p2tr;
+      case SegwitAddresType.p2wsh:
+        return BitcoinReceivePageOption.p2wsh;
+      case P2pkhAddressType.p2pkh:
+        return BitcoinReceivePageOption.p2pkh;
+      case P2shAddressType.p2wpkhInP2sh:
+        return BitcoinReceivePageOption.p2sh;
+      case SegwitAddresType.p2wpkh:
+      default:
+        return BitcoinReceivePageOption.p2wpkh;
+    }
+  }
+}
diff --git a/cw_bitcoin/lib/bitcoin_unspent.dart b/cw_bitcoin/lib/bitcoin_unspent.dart
index 9c198c27c..52edea091 100644
--- a/cw_bitcoin/lib/bitcoin_unspent.dart
+++ b/cw_bitcoin/lib/bitcoin_unspent.dart
@@ -6,10 +6,9 @@ class BitcoinUnspent extends Unspent {
       : bitcoinAddressRecord = addressRecord,
         super(addressRecord.address, hash, value, vout, null);
 
-  factory BitcoinUnspent.fromJSON(
-      BitcoinAddressRecord address, Map<String, dynamic> json) =>
-      BitcoinUnspent(address, json['tx_hash'] as String, json['value'] as int,
-          json['tx_pos'] as int);
+  factory BitcoinUnspent.fromJSON(BitcoinAddressRecord address, Map<String, dynamic> json) =>
+      BitcoinUnspent(
+          address, json['tx_hash'] as String, json['value'] as int, json['tx_pos'] as int);
 
   final BitcoinAddressRecord bitcoinAddressRecord;
 }
diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart
index 403c53b1d..3b3e9c636 100644
--- a/cw_bitcoin/lib/bitcoin_wallet.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet.dart
@@ -1,4 +1,4 @@
-
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
 import 'package:cw_core/crypto_currency.dart';
 import 'package:cw_core/unspent_coins_info.dart';
@@ -18,59 +18,72 @@ part 'bitcoin_wallet.g.dart';
 class BitcoinWallet = BitcoinWalletBase with _$BitcoinWallet;
 
 abstract class BitcoinWalletBase extends ElectrumWallet with Store {
-  BitcoinWalletBase(
-      {required String mnemonic,
-      required String password,
-      required WalletInfo walletInfo,
-      required Box<UnspentCoinsInfo> unspentCoinsInfo,
-      required Uint8List seedBytes,
-      List<BitcoinAddressRecord>? initialAddresses,
-      ElectrumBalance? initialBalance,
-      int initialRegularAddressIndex = 0,
-      int initialChangeAddressIndex = 0})
-      : super(
+  BitcoinWalletBase({
+    required String mnemonic,
+    required String password,
+    required WalletInfo walletInfo,
+    required Box<UnspentCoinsInfo> unspentCoinsInfo,
+    required Uint8List seedBytes,
+    String? addressPageType,
+    BasedUtxoNetwork? networkParam,
+    List<BitcoinAddressRecord>? initialAddresses,
+    ElectrumBalance? initialBalance,
+    Map<String, int>? initialRegularAddressIndex,
+    Map<String, int>? initialChangeAddressIndex,
+  }) : super(
             mnemonic: mnemonic,
             password: password,
             walletInfo: walletInfo,
             unspentCoinsInfo: unspentCoinsInfo,
-            networkType: bitcoin.bitcoin,
+            networkType: networkParam == null
+                ? bitcoin.bitcoin
+                : networkParam == BitcoinNetwork.mainnet
+                    ? bitcoin.bitcoin
+                    : bitcoin.testnet,
             initialAddresses: initialAddresses,
             initialBalance: initialBalance,
             seedBytes: seedBytes,
             currency: CryptoCurrency.btc) {
-    walletAddresses = BitcoinWalletAddresses(walletInfo,
-        electrumClient: electrumClient,
-        initialAddresses: initialAddresses,
-        initialRegularAddressIndex: initialRegularAddressIndex,
-        initialChangeAddressIndex: initialChangeAddressIndex,
-        mainHd: hd,
-        sideHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/1"),
-        networkType: networkType);
-
+    walletAddresses = BitcoinWalletAddresses(
+      walletInfo,
+      electrumClient: electrumClient,
+      initialAddresses: initialAddresses,
+      initialRegularAddressIndex: initialRegularAddressIndex,
+      initialChangeAddressIndex: initialChangeAddressIndex,
+      mainHd: hd,
+      sideHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/1"),
+      network: networkParam ?? network,
+    );
     autorun((_) {
       this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
     });
   }
 
-  static Future<BitcoinWallet> create(
-      {required String mnemonic,
-      required String password,
-      required WalletInfo walletInfo,
-      required Box<UnspentCoinsInfo> unspentCoinsInfo,
-      List<BitcoinAddressRecord>? initialAddresses,
-      ElectrumBalance? initialBalance,
-      int initialRegularAddressIndex = 0,
-      int initialChangeAddressIndex = 0}) async {
+  static Future<BitcoinWallet> create({
+    required String mnemonic,
+    required String password,
+    required WalletInfo walletInfo,
+    required Box<UnspentCoinsInfo> unspentCoinsInfo,
+    String? addressPageType,
+    BasedUtxoNetwork? network,
+    List<BitcoinAddressRecord>? initialAddresses,
+    ElectrumBalance? initialBalance,
+    Map<String, int>? initialRegularAddressIndex,
+    Map<String, int>? initialChangeAddressIndex,
+  }) async {
     return BitcoinWallet(
-        mnemonic: mnemonic,
-        password: password,
-        walletInfo: walletInfo,
-        unspentCoinsInfo: unspentCoinsInfo,
-        initialAddresses: initialAddresses,
-        initialBalance: initialBalance,
-        seedBytes: await mnemonicToSeedBytes(mnemonic),
-        initialRegularAddressIndex: initialRegularAddressIndex,
-        initialChangeAddressIndex: initialChangeAddressIndex);
+      mnemonic: mnemonic,
+      password: password,
+      walletInfo: walletInfo,
+      unspentCoinsInfo: unspentCoinsInfo,
+      initialAddresses: initialAddresses,
+      initialBalance: initialBalance,
+      seedBytes: await mnemonicToSeedBytes(mnemonic),
+      initialRegularAddressIndex: initialRegularAddressIndex,
+      initialChangeAddressIndex: initialChangeAddressIndex,
+      addressPageType: addressPageType,
+      networkParam: network,
+    );
   }
 
   static Future<BitcoinWallet> open({
@@ -79,16 +92,21 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
     required Box<UnspentCoinsInfo> unspentCoinsInfo,
     required String password,
   }) async {
-    final snp = await ElectrumWallletSnapshot.load(name, walletInfo.type, password);
+    final snp = await ElectrumWalletSnapshot.load(name, walletInfo.type, password,
+        walletInfo.network != null ? BasedUtxoNetwork.fromName(walletInfo.network!) : null);
+
     return BitcoinWallet(
-        mnemonic: snp.mnemonic,
-        password: password,
-        walletInfo: walletInfo,
-        unspentCoinsInfo: unspentCoinsInfo,
-        initialAddresses: snp.addresses,
-        initialBalance: snp.balance,
-        seedBytes: await mnemonicToSeedBytes(snp.mnemonic),
-        initialRegularAddressIndex: snp.regularAddressIndex,
-        initialChangeAddressIndex: snp.changeAddressIndex);
+      mnemonic: snp.mnemonic,
+      password: password,
+      walletInfo: walletInfo,
+      unspentCoinsInfo: unspentCoinsInfo,
+      initialAddresses: snp.addresses,
+      initialBalance: snp.balance,
+      seedBytes: await mnemonicToSeedBytes(snp.mnemonic),
+      initialRegularAddressIndex: snp.regularAddressIndex,
+      initialChangeAddressIndex: snp.changeAddressIndex,
+      addressPageType: snp.addressPageType,
+      networkParam: snp.network,
+    );
   }
 }
diff --git a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart
index 36d37127d..f12577492 100644
--- a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart
@@ -1,6 +1,5 @@
-import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
-import 'package:cw_bitcoin/bitcoin_address_record.dart';
-import 'package:cw_bitcoin/electrum.dart';
+import 'package:bitcoin_base/bitcoin_base.dart';
+import 'package:bitcoin_flutter/bitcoin_flutter.dart';
 import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
 import 'package:cw_bitcoin/utils.dart';
 import 'package:cw_core/wallet_info.dart';
@@ -11,24 +10,31 @@ part 'bitcoin_wallet_addresses.g.dart';
 class BitcoinWalletAddresses = BitcoinWalletAddressesBase with _$BitcoinWalletAddresses;
 
 abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with Store {
-  BitcoinWalletAddressesBase(WalletInfo walletInfo,
-      {required bitcoin.HDWallet mainHd,
-      required bitcoin.HDWallet sideHd,
-      required bitcoin.NetworkType networkType,
-      required ElectrumClient electrumClient,
-      List<BitcoinAddressRecord>? initialAddresses,
-      int initialRegularAddressIndex = 0,
-      int initialChangeAddressIndex = 0})
-      : super(walletInfo,
-            initialAddresses: initialAddresses,
-            initialRegularAddressIndex: initialRegularAddressIndex,
-            initialChangeAddressIndex: initialChangeAddressIndex,
-            mainHd: mainHd,
-            sideHd: sideHd,
-            electrumClient: electrumClient,
-            networkType: networkType);
+  BitcoinWalletAddressesBase(
+    WalletInfo walletInfo, {
+    required super.mainHd,
+    required super.sideHd,
+    required super.network,
+    required super.electrumClient,
+    super.initialAddresses,
+    super.initialRegularAddressIndex,
+    super.initialChangeAddressIndex,
+  }) : super(walletInfo);
 
   @override
-  String getAddress({required int index, required bitcoin.HDWallet hd}) =>
-      generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
+  String getAddress({required int index, required HDWallet hd, BitcoinAddressType? addressType}) {
+    if (addressType == P2pkhAddressType.p2pkh)
+      return generateP2PKHAddress(hd: hd, index: index, network: network);
+
+    if (addressType == SegwitAddresType.p2tr)
+      return generateP2TRAddress(hd: hd, index: index, network: network);
+
+    if (addressType == SegwitAddresType.p2wsh)
+      return generateP2WSHAddress(hd: hd, index: index, network: network);
+
+    if (addressType == P2shAddressType.p2wpkhInP2sh)
+      return generateP2SHAddress(hd: hd, index: index, network: network);
+
+    return generateP2WPKHAddress(hd: hd, index: index, network: network);
+  }
 }
diff --git a/cw_bitcoin/lib/bitcoin_wallet_service.dart b/cw_bitcoin/lib/bitcoin_wallet_service.dart
index 736ec1044..2b8c489d2 100644
--- a/cw_bitcoin/lib/bitcoin_wallet_service.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet_service.dart
@@ -1,4 +1,5 @@
 import 'dart:io';
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
 import 'package:cw_bitcoin/bitcoin_mnemonic_is_incorrect_exception.dart';
 import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
@@ -23,12 +24,17 @@ class BitcoinWalletService extends WalletService<BitcoinNewWalletCredentials,
   WalletType getType() => WalletType.bitcoin;
 
   @override
-  Future<BitcoinWallet> create(BitcoinNewWalletCredentials credentials) async {
+  Future<BitcoinWallet> create(BitcoinNewWalletCredentials credentials, {bool? isTestnet}) async {
+    final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet;
+    credentials.walletInfo?.network = network.value;
+
     final wallet = await BitcoinWalletBase.create(
-        mnemonic: await generateMnemonic(),
-        password: credentials.password!,
-        walletInfo: credentials.walletInfo!,
-        unspentCoinsInfo: unspentCoinsInfoSource);
+      mnemonic: await generateMnemonic(),
+      password: credentials.password!,
+      walletInfo: credentials.walletInfo!,
+      unspentCoinsInfo: unspentCoinsInfoSource,
+      network: network,
+    );
     await wallet.save();
     await wallet.init();
     return wallet;
@@ -92,20 +98,27 @@ class BitcoinWalletService extends WalletService<BitcoinNewWalletCredentials,
   }
 
   @override
-  Future<BitcoinWallet> restoreFromKeys(BitcoinRestoreWalletFromWIFCredentials credentials) async =>
+  Future<BitcoinWallet> restoreFromKeys(BitcoinRestoreWalletFromWIFCredentials credentials,
+          {bool? isTestnet}) async =>
       throw UnimplementedError();
 
   @override
-  Future<BitcoinWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials) async {
+  Future<BitcoinWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials,
+      {bool? isTestnet}) async {
     if (!validateMnemonic(credentials.mnemonic)) {
       throw BitcoinMnemonicIsIncorrectException();
     }
 
+    final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet;
+    credentials.walletInfo?.network = network.value;
+
     final wallet = await BitcoinWalletBase.create(
-        password: credentials.password!,
-        mnemonic: credentials.mnemonic,
-        walletInfo: credentials.walletInfo!,
-        unspentCoinsInfo: unspentCoinsInfoSource);
+      password: credentials.password!,
+      mnemonic: credentials.mnemonic,
+      walletInfo: credentials.walletInfo!,
+      unspentCoinsInfo: unspentCoinsInfoSource,
+      network: network,
+    );
     await wallet.save();
     await wallet.init();
     return wallet;
diff --git a/cw_bitcoin/lib/electrum.dart b/cw_bitcoin/lib/electrum.dart
index a05c251fe..51a53e285 100644
--- a/cw_bitcoin/lib/electrum.dart
+++ b/cw_bitcoin/lib/electrum.dart
@@ -2,12 +2,12 @@ import 'dart:async';
 import 'dart:convert';
 import 'dart:io';
 import 'dart:typed_data';
-import 'package:bitcoin_flutter/bitcoin_flutter.dart';
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:cw_bitcoin/bitcoin_amount_format.dart';
 import 'package:cw_bitcoin/script_hash.dart';
 import 'package:flutter/foundation.dart';
 import 'package:rxdart/rxdart.dart';
-import 'package:collection/collection.dart';
+import 'package:http/http.dart' as http;
 
 String jsonrpcparams(List<Object> params) {
   final _params = params?.map((val) => '"${val.toString()}"')?.join(',');
@@ -22,10 +22,7 @@ String jsonrpc(
     '{"jsonrpc": "$version", "method": "$method", "id": "$id",  "params": ${json.encode(params)}}\n';
 
 class SocketTask {
-  SocketTask({
-    required this.isSubscription,
-    this.completer,
-    this.subject});
+  SocketTask({required this.isSubscription, this.completer, this.subject});
 
   final Completer<dynamic>? completer;
   final BehaviorSubject<dynamic>? subject;
@@ -51,8 +48,7 @@ class ElectrumClient {
   Timer? _aliveTimer;
   String unterminatedString;
 
-  Future<void> connectToUri(Uri uri) async =>
-    await connect(host: uri.host, port: uri.port);
+  Future<void> connectToUri(Uri uri) async => await connect(host: uri.host, port: uri.port);
 
   Future<void> connect({required String host, required int port}) async {
     try {
@@ -104,21 +100,20 @@ class ElectrumClient {
       }
 
       if (isJSONStringCorrect(unterminatedString)) {
-        final response =
-        json.decode(unterminatedString) as Map<String, dynamic>;
+        final response = json.decode(unterminatedString) as Map<String, dynamic>;
         _handleResponse(response);
         unterminatedString = '';
       }
     } on TypeError catch (e) {
-      if (!e.toString().contains('Map<String, Object>') && !e.toString().contains('Map<String, dynamic>')) {
+      if (!e.toString().contains('Map<String, Object>') &&
+          !e.toString().contains('Map<String, dynamic>')) {
         return;
       }
 
       unterminatedString += message;
 
       if (isJSONStringCorrect(unterminatedString)) {
-        final response =
-        json.decode(unterminatedString) as Map<String, dynamic>;
+        final response = json.decode(unterminatedString) as Map<String, dynamic>;
         _handleResponse(response);
         // unterminatedString = null;
         unterminatedString = '';
@@ -142,8 +137,7 @@ class ElectrumClient {
     }
   }
 
-  Future<List<String>> version() =>
-      call(method: 'server.version').then((dynamic result) {
+  Future<List<String>> version() => call(method: 'server.version').then((dynamic result) {
         if (result is List) {
           return result.map((dynamic val) => val.toString()).toList();
         }
@@ -178,11 +172,10 @@ class ElectrumClient {
       });
 
   Future<List<Map<String, dynamic>>> getListUnspentWithAddress(
-          String address, NetworkType networkType) =>
+          String address, BasedUtxoNetwork network) =>
       call(
-              method: 'blockchain.scripthash.listunspent',
-              params: [scriptHash(address, networkType: networkType)])
-          .then((dynamic result) {
+          method: 'blockchain.scripthash.listunspent',
+          params: [scriptHash(address, network: network)]).then((dynamic result) {
         if (result is List) {
           return result.map((dynamic val) {
             if (val is Map<String, dynamic>) {
@@ -229,8 +222,7 @@ class ElectrumClient {
         return [];
       });
 
-  Future<Map<String, dynamic>> getTransactionRaw(
-          {required String hash}) async =>
+  Future<Map<String, dynamic>> getTransactionRaw({required String hash}) async =>
       callWithTimeout(method: 'blockchain.transaction.get', params: [hash, true], timeout: 10000)
           .then((dynamic result) {
         if (result is Map<String, dynamic>) {
@@ -240,8 +232,7 @@ class ElectrumClient {
         return <String, dynamic>{};
       });
 
-  Future<String> getTransactionHex(
-          {required String hash}) async =>
+  Future<String> getTransactionHex({required String hash}) async =>
       callWithTimeout(method: 'blockchain.transaction.get', params: [hash, false], timeout: 10000)
           .then((dynamic result) {
         if (result is String) {
@@ -252,29 +243,40 @@ class ElectrumClient {
       });
 
   Future<String> broadcastTransaction(
-          {required String transactionRaw}) async =>
-      call(method: 'blockchain.transaction.broadcast', params: [transactionRaw])
-          .then((dynamic result) {
-        if (result is String) {
-          return result;
+      {required String transactionRaw, BasedUtxoNetwork? network}) async {
+    if (network == BitcoinNetwork.testnet) {
+      return http
+          .post(Uri(scheme: 'https', host: 'blockstream.info', path: '/testnet/api/tx'),
+              headers: <String, String>{'Content-Type': 'application/json; charset=utf-8'},
+              body: transactionRaw)
+          .then((http.Response response) {
+        if (response.statusCode == 200) {
+          return response.body;
         }
 
-        return '';
+        throw Exception('Failed to broadcast transaction: ${response.body}');
       });
+    }
 
-  Future<Map<String, dynamic>> getMerkle(
-          {required String hash, required int height}) async =>
-      await call(
-          method: 'blockchain.transaction.get_merkle',
-          params: [hash, height]) as Map<String, dynamic>;
+    return call(method: 'blockchain.transaction.broadcast', params: [transactionRaw])
+        .then((dynamic result) {
+      if (result is String) {
+        return result;
+      }
 
-  Future<Map<String, dynamic>> getHeader({required int height}) async =>
-      await call(method: 'blockchain.block.get_header', params: [height])
+      return '';
+    });
+  }
+
+  Future<Map<String, dynamic>> getMerkle({required String hash, required int height}) async =>
+      await call(method: 'blockchain.transaction.get_merkle', params: [hash, height])
           as Map<String, dynamic>;
 
+  Future<Map<String, dynamic>> getHeader({required int height}) async =>
+      await call(method: 'blockchain.block.get_header', params: [height]) as Map<String, dynamic>;
+
   Future<double> estimatefee({required int p}) =>
-      call(method: 'blockchain.estimatefee', params: [p])
-          .then((dynamic result) {
+      call(method: 'blockchain.estimatefee', params: [p]).then((dynamic result) {
         if (result is double) {
           return result;
         }
@@ -314,20 +316,17 @@ class ElectrumClient {
         return [];
       });
 
-  Future<List<int>> feeRates() async {
+  Future<List<int>> feeRates({BasedUtxoNetwork? network}) async {
+    if (network == BitcoinNetwork.testnet) {
+      return [1, 1, 1];
+    }
     try {
       final topDoubleString = await estimatefee(p: 1);
       final middleDoubleString = await estimatefee(p: 5);
       final bottomDoubleString = await estimatefee(p: 100);
-      final top =
-          (stringDoubleToBitcoinAmount(topDoubleString.toString()) / 1000)
-              .round();
-      final middle =
-          (stringDoubleToBitcoinAmount(middleDoubleString.toString()) / 1000)
-              .round();
-      final bottom =
-          (stringDoubleToBitcoinAmount(bottomDoubleString.toString()) / 1000)
-              .round();
+      final top = (stringDoubleToBitcoinAmount(topDoubleString.toString()) / 1000).round();
+      final middle = (stringDoubleToBitcoinAmount(middleDoubleString.toString()) / 1000).round();
+      final bottom = (stringDoubleToBitcoinAmount(bottomDoubleString.toString()) / 1000).round();
 
       return [bottom, middle, top];
     } catch (_) {
@@ -335,6 +334,21 @@ class ElectrumClient {
     }
   }
 
+  // https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-headers-subscribe
+  // example response:
+  // {
+  //   "height": 520481,
+  //   "hex": "00000020890208a0ae3a3892aa047c5468725846577cfcd9b512b50000000000000000005dc2b02f2d297a9064ee103036c14d678f9afc7e3d9409cf53fd58b82e938e8ecbeca05a2d2103188ce804c4"
+  // }
+  Future<int?> getCurrentBlockChainTip() =>
+      call(method: 'blockchain.headers.subscribe').then((result) {
+        if (result is Map<String, dynamic>) {
+          return result["height"] as int;
+        }
+
+        return null;
+      });
+
   BehaviorSubject<Object>? scripthashUpdate(String scripthash) {
     _id += 1;
     return subscribe<Object>(
@@ -344,16 +358,14 @@ class ElectrumClient {
   }
 
   BehaviorSubject<T>? subscribe<T>(
-      {required String id,
-      required String method,
-      List<Object> params = const []}) {
+      {required String id, required String method, List<Object> params = const []}) {
     try {
       final subscription = BehaviorSubject<T>();
       _regisrySubscription(id, subscription);
       socket!.write(jsonrpc(method: method, id: _id, params: params));
 
       return subscription;
-    } catch(e) {
+    } catch (e) {
       print(e.toString());
       return null;
     }
@@ -370,9 +382,7 @@ class ElectrumClient {
   }
 
   Future<dynamic> callWithTimeout(
-      {required String method,
-      List<Object> params = const [],
-      int timeout = 4000}) async {
+      {required String method, List<Object> params = const [], int timeout = 4000}) async {
     try {
       final completer = Completer<dynamic>();
       _id += 1;
@@ -386,7 +396,7 @@ class ElectrumClient {
       });
 
       return completer.future;
-    } catch(e) {
+    } catch (e) {
       print(e.toString());
     }
   }
@@ -397,8 +407,8 @@ class ElectrumClient {
     onConnectionStatusChange = null;
   }
 
-  void _registryTask(int id, Completer<dynamic> completer) => _tasks[id.toString()] =
-      SocketTask(completer: completer, isSubscription: false);
+  void _registryTask(int id, Completer<dynamic> completer) =>
+      _tasks[id.toString()] = SocketTask(completer: completer, isSubscription: false);
 
   void _regisrySubscription(String id, BehaviorSubject<dynamic> subject) =>
       _tasks[id] = SocketTask(subject: subject, isSubscription: true);
@@ -419,8 +429,7 @@ class ElectrumClient {
     }
   }
 
-  void _methodHandler(
-      {required String method, required Map<String, dynamic> request}) {
+  void _methodHandler({required String method, required Map<String, dynamic> request}) {
     switch (method) {
       case 'blockchain.scripthash.subscribe':
         final params = request['params'] as List<dynamic>;
@@ -451,8 +460,8 @@ class ElectrumClient {
       _methodHandler(method: method, request: response);
       return;
     }
-    
-    if (id != null){
+
+    if (id != null) {
       _finish(id, result);
     }
   }
diff --git a/cw_bitcoin/lib/electrum_transaction_info.dart b/cw_bitcoin/lib/electrum_transaction_info.dart
index bf5ec2c4f..cfea0e089 100644
--- a/cw_bitcoin/lib/electrum_transaction_info.dart
+++ b/cw_bitcoin/lib/electrum_transaction_info.dart
@@ -1,3 +1,4 @@
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
 import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
 import 'package:cw_bitcoin/address_from_output.dart';
@@ -10,13 +11,12 @@ import 'package:cw_core/wallet_type.dart';
 
 class ElectrumTransactionBundle {
   ElectrumTransactionBundle(this.originalTransaction,
-    {required this.ins,
-    required this.confirmations,
-    this.time});
-  final bitcoin.Transaction originalTransaction;
-  final List<bitcoin.Transaction> ins;
+      {required this.ins, required this.confirmations, this.time, required this.height});
+  final BtcTransaction originalTransaction;
+  final List<BtcTransaction> ins;
   final int? time;
   final int confirmations;
+  final int height;
 }
 
 class ElectrumTransactionInfo extends TransactionInfo {
@@ -39,8 +39,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
     this.confirmations = confirmations;
   }
 
-  factory ElectrumTransactionInfo.fromElectrumVerbose(
-      Map<String, Object> obj, WalletType type,
+  factory ElectrumTransactionInfo.fromElectrumVerbose(Map<String, Object> obj, WalletType type,
       {required List<BitcoinAddressRecord> addresses, required int height}) {
     final addressesSet = addresses.map((addr) => addr.address).toSet();
     final id = obj['txid'] as String;
@@ -58,10 +57,8 @@ class ElectrumTransactionInfo extends TransactionInfo {
     for (dynamic vin in vins) {
       final vout = vin['vout'] as int;
       final out = vin['tx']['vout'][vout] as Map;
-      final outAddresses =
-          (out['scriptPubKey']['addresses'] as List<Object>?)?.toSet();
-      inputsAmount +=
-          stringDoubleToBitcoinAmount((out['value'] as double? ?? 0).toString());
+      final outAddresses = (out['scriptPubKey']['addresses'] as List<Object>?)?.toSet();
+      inputsAmount += stringDoubleToBitcoinAmount((out['value'] as double? ?? 0).toString());
 
       if (outAddresses?.intersection(addressesSet).isNotEmpty ?? false) {
         direction = TransactionDirection.outgoing;
@@ -69,11 +66,9 @@ class ElectrumTransactionInfo extends TransactionInfo {
     }
 
     for (dynamic out in vout) {
-      final outAddresses =
-          out['scriptPubKey']['addresses'] as List<Object>? ?? [];
+      final outAddresses = out['scriptPubKey']['addresses'] as List<Object>? ?? [];
       final ntrs = outAddresses.toSet().intersection(addressesSet);
-      final value = stringDoubleToBitcoinAmount(
-          (out['value'] as double? ?? 0.0).toString());
+      final value = stringDoubleToBitcoinAmount((out['value'] as double? ?? 0.0).toString());
       totalOutAmount += value;
 
       if ((direction == TransactionDirection.incoming && ntrs.isNotEmpty) ||
@@ -96,44 +91,50 @@ class ElectrumTransactionInfo extends TransactionInfo {
   }
 
   factory ElectrumTransactionInfo.fromElectrumBundle(
-      ElectrumTransactionBundle bundle,
-      WalletType type,
-      bitcoin.NetworkType networkType,
-      {required Set<String> addresses,
-        required int height}) {
+      ElectrumTransactionBundle bundle, WalletType type, BasedUtxoNetwork network,
+      {required Set<String> addresses, required int height}) {
     final date = bundle.time != null
-      ? DateTime.fromMillisecondsSinceEpoch(bundle.time! * 1000)
-      : DateTime.now();
+        ? DateTime.fromMillisecondsSinceEpoch(bundle.time! * 1000)
+        : DateTime.now();
     var direction = TransactionDirection.incoming;
     var amount = 0;
     var inputAmount = 0;
     var totalOutAmount = 0;
 
-    for (var i = 0; i < bundle.originalTransaction.ins.length; i++) {
-      final input = bundle.originalTransaction.ins[i];
+    for (var i = 0; i < bundle.originalTransaction.inputs.length; i++) {
+      final input = bundle.originalTransaction.inputs[i];
       final inputTransaction = bundle.ins[i];
-      final vout = input.index;
-      final outTransaction = inputTransaction.outs[vout!];
-      final address = addressFromOutput(outTransaction.script!, networkType);
-      inputAmount += outTransaction.value!;
-      if (addresses.contains(address)) {
+      final outTransaction = inputTransaction.outputs[input.txIndex];
+      inputAmount += outTransaction.amount.toInt();
+      if (addresses.contains(addressFromOutputScript(outTransaction.scriptPubKey, network))) {
         direction = TransactionDirection.outgoing;
       }
     }
 
-    for (final out in bundle.originalTransaction.outs) {
-      totalOutAmount += out.value!;
-      final address = addressFromOutput(out.script!, networkType);
-      final addressExists = addresses.contains(address);
+    final receivedAmounts = <int>[];
+    for (final out in bundle.originalTransaction.outputs) {
+      totalOutAmount += out.amount.toInt();
+      final addressExists = addresses.contains(addressFromOutputScript(out.scriptPubKey, network));
+
+      if (addressExists) {
+        receivedAmounts.add(out.amount.toInt());
+      }
+
       if ((direction == TransactionDirection.incoming && addressExists) ||
           (direction == TransactionDirection.outgoing && !addressExists)) {
-        amount += out.value!;
+        amount += out.amount.toInt();
       }
     }
 
+    if (receivedAmounts.length == bundle.originalTransaction.outputs.length) {
+      // Self-send
+      direction = TransactionDirection.incoming;
+      amount = receivedAmounts.reduce((a, b) => a + b);
+    }
+
     final fee = inputAmount - totalOutAmount;
     return ElectrumTransactionInfo(type,
-        id: bundle.originalTransaction.getId(),
+        id: bundle.originalTransaction.txId(),
         height: height,
         isPending: bundle.confirmations == 0,
         fee: fee,
@@ -152,8 +153,8 @@ class ElectrumTransactionInfo extends TransactionInfo {
     if (addresses != null) {
       tx.outs.forEach((out) {
         try {
-          final p2pkh = bitcoin.P2PKH(
-              data: PaymentData(output: out.script), network: bitcoin.bitcoin);
+          final p2pkh =
+              bitcoin.P2PKH(data: PaymentData(output: out.script), network: bitcoin.bitcoin);
           exist = addresses.contains(p2pkh.data.address);
 
           if (exist) {
@@ -163,9 +164,8 @@ class ElectrumTransactionInfo extends TransactionInfo {
       });
     }
 
-    final date = timestamp != null
-        ? DateTime.fromMillisecondsSinceEpoch(timestamp * 1000)
-        : DateTime.now();
+    final date =
+        timestamp != null ? DateTime.fromMillisecondsSinceEpoch(timestamp * 1000) : DateTime.now();
 
     return ElectrumTransactionInfo(type,
         id: tx.getId(),
@@ -178,8 +178,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
         confirmations: confirmations);
   }
 
-  factory ElectrumTransactionInfo.fromJson(
-      Map<String, dynamic> data, WalletType type) {
+  factory ElectrumTransactionInfo.fromJson(Map<String, dynamic> data, WalletType type) {
     return ElectrumTransactionInfo(type,
         id: data['id'] as String,
         height: data['height'] as int,
diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart
index 8a41c1733..873fe2977 100644
--- a/cw_bitcoin/lib/electrum_wallet.dart
+++ b/cw_bitcoin/lib/electrum_wallet.dart
@@ -3,9 +3,10 @@ import 'dart:convert';
 import 'dart:io';
 import 'dart:math';
 
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
+import 'package:bitcoin_base/bitcoin_base.dart' as bitcoin_base;
 import 'package:collection/collection.dart';
-import 'package:cw_bitcoin/address_to_output_script.dart';
 import 'package:cw_bitcoin/bitcoin_address_record.dart';
 import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
 import 'package:cw_bitcoin/bitcoin_transaction_no_inputs_exception.dart';
@@ -18,6 +19,7 @@ import 'package:cw_bitcoin/electrum_balance.dart';
 import 'package:cw_bitcoin/electrum_transaction_history.dart';
 import 'package:cw_bitcoin/electrum_transaction_info.dart';
 import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
+import 'package:cw_bitcoin/litecoin_network.dart';
 import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
 import 'package:cw_bitcoin/script_hash.dart';
 import 'package:cw_bitcoin/utils.dart';
@@ -37,6 +39,7 @@ import 'package:hex/hex.dart';
 import 'package:hive/hive.dart';
 import 'package:mobx/mobx.dart';
 import 'package:rxdart/subjects.dart';
+import 'package:http/http.dart' as http;
 
 part 'electrum_wallet.g.dart';
 
@@ -73,6 +76,12 @@ abstract class ElectrumWalletBase
               }
             : {}),
         this.unspentCoinsInfo = unspentCoinsInfo,
+        this.network = networkType == bitcoin.bitcoin
+            ? BitcoinNetwork.mainnet
+            : networkType == litecoinNetwork
+                ? LitecoinNetwork.mainnet
+                : BitcoinNetwork.testnet,
+        this.isTestnet = networkType == bitcoin.testnet,
         super(walletInfo) {
     this.electrumClient = electrumClient ?? ElectrumClient();
     this.walletInfo = walletInfo;
@@ -106,13 +115,13 @@ abstract class ElectrumWalletBase
   @observable
   SyncStatus syncStatus;
 
-  List<String> get scriptHashes => walletAddresses.addresses
-      .map((addr) => scriptHash(addr.address, networkType: networkType))
+  List<String> get scriptHashes => walletAddresses.addressesByReceiveType
+      .map((addr) => scriptHash(addr.address, network: network))
       .toList();
 
-  List<String> get publicScriptHashes => walletAddresses.addresses
+  List<String> get publicScriptHashes => walletAddresses.allAddresses
       .where((addr) => !addr.isHidden)
-      .map((addr) => scriptHash(addr.address, networkType: networkType))
+      .map((addr) => scriptHash(addr.address, network: network))
       .toList();
 
   String get xpub => hd.base58!;
@@ -121,6 +130,10 @@ abstract class ElectrumWalletBase
   String get seed => mnemonic;
 
   bitcoin.NetworkType networkType;
+  BasedUtxoNetwork network;
+
+  @override
+  bool? isTestnet;
 
   @override
   BitcoinWalletKeys get keys =>
@@ -145,12 +158,11 @@ abstract class ElectrumWalletBase
   Future<void> startSync() async {
     try {
       syncStatus = AttemptingSyncStatus();
-      await walletAddresses.discoverAddresses();
       await updateTransactions();
       _subscribeForUpdates();
       await updateUnspent();
       await updateBalance();
-      _feeRates = await electrumClient.feeRates();
+      _feeRates = await electrumClient.feeRates(network: network);
 
       Timer.periodic(
           const Duration(minutes: 1), (timer) async => _feeRates = await electrumClient.feeRates());
@@ -181,183 +193,206 @@ abstract class ElectrumWalletBase
     }
   }
 
-  @override
-  Future<PendingTransaction> createTransaction(Object credentials) async {
-    const minAmount = 546;
-    final transactionCredentials = credentials as BitcoinTransactionCredentials;
-    final inputs = <BitcoinUnspent>[];
-    final outputs = transactionCredentials.outputs;
-    final hasMultiDestination = outputs.length > 1;
+  Future<EstimatedTxResult> _estimateTxFeeAndInputsToUse(
+      int credentialsAmount,
+      bool sendAll,
+      List<BitcoinBaseAddress> outputAddresses,
+      List<BitcoinOutput> outputs,
+      BitcoinTransactionCredentials transactionCredentials,
+      {int? inputsCount}) async {
+    final utxos = <UtxoWithAddress>[];
+    List<ECPrivate> privateKeys = [];
+
+    var leftAmount = credentialsAmount;
     var allInputsAmount = 0;
 
-    if (unspentCoins.isEmpty) {
-      await updateUnspent();
-    }
+    for (int i = 0; i < unspentCoins.length; i++) {
+      final utx = unspentCoins[i];
 
-    for (final utx in unspentCoins) {
       if (utx.isSending) {
         allInputsAmount += utx.value;
-        inputs.add(utx);
-      }
-    }
-
-    if (inputs.isEmpty) {
-      throw BitcoinTransactionNoInputsException();
-    }
-
-    final allAmountFee = transactionCredentials.feeRate != null
-        ? feeAmountWithFeeRate(transactionCredentials.feeRate!, inputs.length, outputs.length)
-        : feeAmountForPriority(transactionCredentials.priority!, inputs.length, outputs.length);
-
-    final allAmount = allInputsAmount - allAmountFee;
-
-    var credentialsAmount = 0;
-    var amount = 0;
-    var fee = 0;
-
-    if (hasMultiDestination) {
-      if (outputs.any((item) => item.sendAll || item.formattedCryptoAmount! <= 0)) {
-        throw BitcoinTransactionWrongBalanceException(currency);
-      }
-
-      credentialsAmount = outputs.fold(0, (acc, value) => acc + value.formattedCryptoAmount!);
-
-      if (allAmount - credentialsAmount < minAmount) {
-        throw BitcoinTransactionWrongBalanceException(currency);
-      }
-
-      amount = credentialsAmount;
-
-      if (transactionCredentials.feeRate != null) {
-        fee = calculateEstimatedFeeWithFeeRate(transactionCredentials.feeRate!, amount,
-            outputsCount: outputs.length + 1);
-      } else {
-        fee = calculateEstimatedFee(transactionCredentials.priority, amount,
-            outputsCount: outputs.length + 1);
-      }
-    } else {
-      final output = outputs.first;
-      credentialsAmount = !output.sendAll ? output.formattedCryptoAmount! : 0;
-
-      if (credentialsAmount > allAmount) {
-        throw BitcoinTransactionWrongBalanceException(currency);
-      }
-
-      amount = output.sendAll || allAmount - credentialsAmount < minAmount
-          ? allAmount
-          : credentialsAmount;
-
-      if (output.sendAll || amount == allAmount) {
-        fee = allAmountFee;
-      } else if (transactionCredentials.feeRate != null) {
-        fee = calculateEstimatedFeeWithFeeRate(transactionCredentials.feeRate!, amount);
-      } else {
-        fee = calculateEstimatedFee(transactionCredentials.priority, amount);
-      }
-    }
-
-    if (fee == 0) {
-      throw BitcoinTransactionWrongBalanceException(currency);
-    }
-
-    final totalAmount = amount + fee;
-
-    if (totalAmount > balance[currency]!.confirmed || totalAmount > allInputsAmount) {
-      throw BitcoinTransactionWrongBalanceException(currency);
-    }
-
-    final txb = bitcoin.TransactionBuilder(network: networkType);
-    final changeAddress = await walletAddresses.getChangeAddress();
-    var leftAmount = totalAmount;
-    var totalInputAmount = 0;
-
-    inputs.clear();
-
-    for (final utx in unspentCoins) {
-      if (utx.isSending) {
         leftAmount = leftAmount - utx.value;
-        totalInputAmount += utx.value;
-        inputs.add(utx);
 
-        if (leftAmount <= 0) {
+        final address = _addressTypeFromStr(utx.address, network);
+        final privkey = generateECPrivate(
+            hd: utx.bitcoinAddressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd,
+            index: utx.bitcoinAddressRecord.index,
+            network: network);
+
+        privateKeys.add(privkey);
+
+        utxos.add(
+          UtxoWithAddress(
+            utxo: BitcoinUtxo(
+              txHash: utx.hash,
+              value: BigInt.from(utx.value),
+              vout: utx.vout,
+              scriptType: _getScriptType(address),
+            ),
+            ownerDetails:
+                UtxoAddressDetails(publicKey: privkey.getPublic().toHex(), address: address),
+          ),
+        );
+
+        bool amountIsAcquired = !sendAll && leftAmount <= 0;
+        if ((inputsCount == null && amountIsAcquired) || inputsCount == i + 1) {
           break;
         }
       }
     }
 
-    if (inputs.isEmpty) {
+    if (utxos.isEmpty) {
       throw BitcoinTransactionNoInputsException();
     }
 
-    if (amount <= 0 || totalInputAmount < totalAmount) {
+    var changeValue = allInputsAmount - credentialsAmount;
+
+    if (!sendAll) {
+      if (changeValue > 0) {
+        final changeAddress = await walletAddresses.getChangeAddress();
+        final address = _addressTypeFromStr(changeAddress, network);
+        outputAddresses.add(address);
+        outputs.add(BitcoinOutput(address: address, value: BigInt.from(changeValue)));
+      }
+    }
+
+    final estimatedSize = BitcoinTransactionBuilder.estimateTransactionSize(
+        utxos: utxos, outputs: outputs, network: network);
+
+    final fee = transactionCredentials.feeRate != null
+        ? feeAmountWithFeeRate(transactionCredentials.feeRate!, 0, 0, size: estimatedSize)
+        : feeAmountForPriority(transactionCredentials.priority!, 0, 0, size: estimatedSize);
+
+    if (fee == 0) {
       throw BitcoinTransactionWrongBalanceException(currency);
     }
 
-    txb.setVersion(1);
-    inputs.forEach((input) {
-      if (input.isP2wpkh) {
-        final p2wpkh = bitcoin
-            .P2WPKH(
-                data: generatePaymentData(
-                    hd: input.bitcoinAddressRecord.isHidden
-                        ? walletAddresses.sideHd
-                        : walletAddresses.mainHd,
-                    index: input.bitcoinAddressRecord.index),
-                network: networkType)
-            .data;
+    var amount = credentialsAmount;
 
-        txb.addInput(input.hash, input.vout, null, p2wpkh.output);
-      } else {
-        txb.addInput(input.hash, input.vout);
+    final lastOutput = outputs.last;
+    if (!sendAll) {
+      if (changeValue > fee) {
+        // Here, lastOutput is change, deduct the fee from it
+        outputs[outputs.length - 1] =
+            BitcoinOutput(address: lastOutput.address, value: lastOutput.value - BigInt.from(fee));
       }
-    });
-
-    outputs.forEach((item) {
-      final outputAmount = hasMultiDestination ? item.formattedCryptoAmount : amount;
-      final outputAddress = item.isParsedAddress ? item.extractedAddress! : item.address;
-      txb.addOutput(addressToOutputScript(outputAddress, networkType), outputAmount!);
-    });
-
-    final estimatedSize = estimatedTransactionSize(inputs.length, outputs.length + 1);
-    var feeAmount = 0;
-
-    if (transactionCredentials.feeRate != null) {
-      feeAmount = transactionCredentials.feeRate! * estimatedSize;
     } else {
-      feeAmount = feeRate(transactionCredentials.priority!) * estimatedSize;
+      // Here, if sendAll, the output amount equals to the input value - fee to fully spend every input on the transaction and have no amount for change
+      amount = allInputsAmount - fee;
+      outputs[outputs.length - 1] =
+          BitcoinOutput(address: lastOutput.address, value: BigInt.from(amount));
     }
 
-    final changeValue = totalInputAmount - amount - feeAmount;
+    final totalAmount = amount + fee;
 
-    if (changeValue > minAmount) {
-      txb.addOutput(changeAddress, changeValue);
+    if (totalAmount > balance[currency]!.confirmed) {
+      throw BitcoinTransactionWrongBalanceException(currency);
     }
 
-    for (var i = 0; i < inputs.length; i++) {
-      final input = inputs[i];
-      final keyPair = generateKeyPair(
-          hd: input.bitcoinAddressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd,
-          index: input.bitcoinAddressRecord.index,
-          network: networkType);
-      final witnessValue = input.isP2wpkh ? input.value : null;
+    if (totalAmount > allInputsAmount) {
+      if (unspentCoins.where((utx) => utx.isSending).length == utxos.length) {
+        throw BitcoinTransactionWrongBalanceException(currency);
+      } else {
+        if (changeValue > fee) {
+          outputAddresses.removeLast();
+          outputs.removeLast();
+        }
 
-      txb.sign(vin: i, keyPair: keyPair, witnessValue: witnessValue);
+        return _estimateTxFeeAndInputsToUse(
+            credentialsAmount, sendAll, outputAddresses, outputs, transactionCredentials,
+            inputsCount: utxos.length + 1);
+      }
     }
 
-    return PendingBitcoinTransaction(txb.build(), type,
-        electrumClient: electrumClient, amount: amount, fee: fee)
-      ..addListener((transaction) async {
-        transactionHistory.addOne(transaction);
-        await updateBalance();
+    return EstimatedTxResult(utxos: utxos, privateKeys: privateKeys, fee: fee, amount: amount);
+  }
+
+  @override
+  Future<PendingTransaction> createTransaction(Object credentials) async {
+    try {
+      final outputs = <BitcoinOutput>[];
+      final outputAddresses = <BitcoinBaseAddress>[];
+      final transactionCredentials = credentials as BitcoinTransactionCredentials;
+      final hasMultiDestination = transactionCredentials.outputs.length > 1;
+      final sendAll = !hasMultiDestination && transactionCredentials.outputs.first.sendAll;
+
+      var credentialsAmount = 0;
+
+      for (final out in transactionCredentials.outputs) {
+        final outputAddress = out.isParsedAddress ? out.extractedAddress! : out.address;
+        final address = _addressTypeFromStr(outputAddress, network);
+
+        outputAddresses.add(address);
+
+        if (hasMultiDestination) {
+          if (out.sendAll || out.formattedCryptoAmount! <= 0) {
+            throw BitcoinTransactionWrongBalanceException(currency);
+          }
+
+          final outputAmount = out.formattedCryptoAmount!;
+          credentialsAmount += outputAmount;
+
+          outputs.add(BitcoinOutput(address: address, value: BigInt.from(outputAmount)));
+        } else {
+          if (!sendAll) {
+            final outputAmount = out.formattedCryptoAmount!;
+            credentialsAmount += outputAmount;
+            outputs.add(BitcoinOutput(address: address, value: BigInt.from(outputAmount)));
+          } else {
+            // The value will be changed after estimating the Tx size and deducting the fee from the total
+            outputs.add(BitcoinOutput(address: address, value: BigInt.from(0)));
+          }
+        }
+      }
+
+      final estimatedTx = await _estimateTxFeeAndInputsToUse(
+          credentialsAmount, sendAll, outputAddresses, outputs, transactionCredentials);
+
+      final txb = BitcoinTransactionBuilder(
+          utxos: estimatedTx.utxos,
+          outputs: outputs,
+          fee: BigInt.from(estimatedTx.fee),
+          network: network);
+
+      final transaction = txb.buildTransaction((txDigest, utxo, publicKey, sighash) {
+        final key = estimatedTx.privateKeys
+            .firstWhereOrNull((element) => element.getPublic().toHex() == publicKey);
+
+        if (key == null) {
+          throw Exception("Cannot find private key");
+        }
+
+        if (utxo.utxo.isP2tr()) {
+          return key.signTapRoot(txDigest, sighash: sighash);
+        } else {
+          return key.signInput(txDigest, sigHash: sighash);
+        }
       });
+
+      return PendingBitcoinTransaction(transaction, type,
+          electrumClient: electrumClient,
+          amount: estimatedTx.amount,
+          fee: estimatedTx.fee,
+          network: network)
+        ..addListener((transaction) async {
+          transactionHistory.addOne(transaction);
+          await updateBalance();
+        });
+    } catch (e) {
+      throw e;
+    }
   }
 
   String toJSON() => json.encode({
         'mnemonic': mnemonic,
-        'account_index': walletAddresses.currentReceiveAddressIndex.toString(),
-        'change_address_index': walletAddresses.currentChangeAddressIndex.toString(),
-        'addresses': walletAddresses.addresses.map((addr) => addr.toJSON()).toList(),
-        'balance': balance[currency]?.toJSON()
+        'account_index': walletAddresses.currentReceiveAddressIndexByType,
+        'change_address_index': walletAddresses.currentChangeAddressIndexByType,
+        'addresses': walletAddresses.allAddresses.map((addr) => addr.toJSON()).toList(),
+        'address_page_type': walletInfo.addressPageType == null
+            ? SegwitAddresType.p2wpkh.toString()
+            : walletInfo.addressPageType.toString(),
+        'balance': balance[currency]?.toJSON(),
+        'network_type': network == BitcoinNetwork.testnet ? 'testnet' : 'mainnet',
       });
 
   int feeRate(TransactionPriority priority) {
@@ -372,24 +407,29 @@ abstract class ElectrumWalletBase
     }
   }
 
-  int feeAmountForPriority(
-          BitcoinTransactionPriority priority, int inputsCount, int outputsCount) =>
-      feeRate(priority) * estimatedTransactionSize(inputsCount, outputsCount);
+  int feeAmountForPriority(BitcoinTransactionPriority priority, int inputsCount, int outputsCount,
+          {int? size}) =>
+      feeRate(priority) * (size ?? estimatedTransactionSize(inputsCount, outputsCount));
 
-  int feeAmountWithFeeRate(int feeRate, int inputsCount, int outputsCount) =>
-      feeRate * estimatedTransactionSize(inputsCount, outputsCount);
+  int feeAmountWithFeeRate(int feeRate, int inputsCount, int outputsCount, {int? size}) =>
+      feeRate * (size ?? estimatedTransactionSize(inputsCount, outputsCount));
 
   @override
-  int calculateEstimatedFee(TransactionPriority? priority, int? amount, {int? outputsCount}) {
+  int calculateEstimatedFee(TransactionPriority? priority, int? amount,
+      {int? outputsCount, int? size}) {
     if (priority is BitcoinTransactionPriority) {
       return calculateEstimatedFeeWithFeeRate(feeRate(priority), amount,
-          outputsCount: outputsCount);
+          outputsCount: outputsCount, size: size);
     }
 
     return 0;
   }
 
-  int calculateEstimatedFeeWithFeeRate(int feeRate, int? amount, {int? outputsCount}) {
+  int calculateEstimatedFeeWithFeeRate(int feeRate, int? amount, {int? outputsCount, int? size}) {
+    if (size != null) {
+      return feeAmountWithFeeRate(feeRate, 0, 0, size: size);
+    }
+
     int inputsCount = 0;
 
     if (amount != null) {
@@ -457,9 +497,6 @@ abstract class ElectrumWalletBase
     await transactionHistory.changePassword(password);
   }
 
-  bitcoin.ECPair keyPairFor({required int index}) =>
-      generateKeyPair(hd: hd, index: index, network: networkType);
-
   @override
   Future<void> rescan({required int height}) async => throw UnimplementedError();
 
@@ -473,20 +510,23 @@ abstract class ElectrumWalletBase
   Future<String> makePath() async => pathForWallet(name: walletInfo.name, type: walletInfo.type);
 
   Future<void> updateUnspent() async {
-    final unspent = await Future.wait(walletAddresses.addresses.map((address) => electrumClient
-        .getListUnspentWithAddress(address.address, networkType)
-        .then((unspent) => unspent.map((unspent) {
+    List<BitcoinUnspent> updatedUnspentCoins = [];
+
+    final addressesSet = walletAddresses.allAddresses.map((addr) => addr.address).toSet();
+
+    await Future.wait(walletAddresses.allAddresses.map((address) => electrumClient
+        .getListUnspentWithAddress(address.address, network)
+        .then((unspent) => Future.forEach<Map<String, dynamic>>(unspent, (unspent) async {
               try {
-                return BitcoinUnspent.fromJSON(address, unspent);
-              } catch (_) {
-                return null;
-              }
-            }).whereNotNull())));
-    unspentCoins = unspent.expand((e) => e).toList();
-    unspentCoins.forEach((coin) async {
-      final tx = await fetchTransactionInfo(hash: coin.hash, height: 0);
-      coin.isChange = tx?.direction == TransactionDirection.outgoing;
-    });
+                final coin = BitcoinUnspent.fromJSON(address, unspent);
+                final tx = await fetchTransactionInfo(
+                    hash: coin.hash, height: 0, myAddresses: addressesSet);
+                coin.isChange = tx?.direction == TransactionDirection.outgoing;
+                updatedUnspentCoins.add(coin);
+              } catch (_) {}
+            }))));
+
+    unspentCoins = updatedUnspentCoins;
 
     if (unspentCoinsInfo.isEmpty) {
       unspentCoins.forEach((coin) => _addCoinInfo(coin));
@@ -495,8 +535,10 @@ abstract class ElectrumWalletBase
 
     if (unspentCoins.isNotEmpty) {
       unspentCoins.forEach((coin) {
-        final coinInfoList = unspentCoinsInfo.values
-            .where((element) => element.walletId.contains(id) && element.hash.contains(coin.hash));
+        final coinInfoList = unspentCoinsInfo.values.where((element) =>
+            element.walletId.contains(id) &&
+            element.hash.contains(coin.hash) &&
+            element.vout == coin.vout);
 
         if (coinInfoList.isNotEmpty) {
           final coinInfo = coinInfoList.first;
@@ -537,7 +579,8 @@ abstract class ElectrumWalletBase
 
       if (currentWalletUnspentCoins.isNotEmpty) {
         currentWalletUnspentCoins.forEach((element) {
-          final existUnspentCoins = unspentCoins.where((coin) => element.hash.contains(coin.hash));
+          final existUnspentCoins = unspentCoins
+              .where((coin) => element.hash.contains(coin.hash) && element.vout == coin.vout);
 
           if (existUnspentCoins.isEmpty) {
             keys.add(element.key);
@@ -555,92 +598,152 @@ abstract class ElectrumWalletBase
 
   Future<ElectrumTransactionBundle> getTransactionExpanded(
       {required String hash, required int height}) async {
-    final verboseTransaction = await electrumClient.getTransactionRaw(hash: hash);
-    final transactionHex = verboseTransaction['hex'] as String;
-    final original = bitcoin.Transaction.fromHex(transactionHex);
-    final ins = <bitcoin.Transaction>[];
-    final time = verboseTransaction['time'] as int?;
-    final confirmations = verboseTransaction['confirmations'] as int? ?? 0;
+    String transactionHex;
+    int? time;
+    int confirmations = 0;
+    if (network == BitcoinNetwork.testnet) {
+      // Testnet public electrum server does not support verbose transaction fetching
+      transactionHex = await electrumClient.getTransactionHex(hash: hash);
 
-    for (final vin in original.ins) {
-      final id = HEX.encode(vin.hash!.reversed.toList());
-      final txHex = await electrumClient.getTransactionHex(hash: id);
-      final tx = bitcoin.Transaction.fromHex(txHex);
-      ins.add(tx);
+      final status = json.decode(
+          (await http.get(Uri.parse("https://blockstream.info/testnet/api/tx/$hash/status"))).body);
+
+      time = status["block_time"] as int?;
+      final tip = await electrumClient.getCurrentBlockChainTip() ?? 0;
+      confirmations = tip - (status["block_height"] as int? ?? 0);
+    } else {
+      final verboseTransaction = await electrumClient.getTransactionRaw(hash: hash);
+
+      transactionHex = verboseTransaction['hex'] as String;
+      time = verboseTransaction['time'] as int?;
+      confirmations = verboseTransaction['confirmations'] as int? ?? 0;
     }
 
-    return ElectrumTransactionBundle(original, ins: ins, time: time, confirmations: confirmations);
+    final original = bitcoin_base.BtcTransaction.fromRaw(transactionHex);
+    final ins = <bitcoin_base.BtcTransaction>[];
+
+    for (final vin in original.inputs) {
+      try {
+        final id = HEX.encode(HEX.decode(vin.txId).reversed.toList());
+        final txHex = await electrumClient.getTransactionHex(hash: id);
+        final tx = bitcoin_base.BtcTransaction.fromRaw(txHex);
+        ins.add(tx);
+      } catch (_) {
+        ins.add(bitcoin_base.BtcTransaction.fromRaw(
+          await electrumClient.getTransactionHex(hash: vin.txId),
+        ));
+      }
+    }
+
+    return ElectrumTransactionBundle(original,
+        ins: ins, time: time, confirmations: confirmations, height: height);
   }
 
   Future<ElectrumTransactionInfo?> fetchTransactionInfo(
-      {required String hash, required int height}) async {
+      {required String hash,
+      required int height,
+      required Set<String> myAddresses,
+      bool? retryOnFailure}) async {
     try {
-      final tx = await getTransactionExpanded(hash: hash, height: height);
-      final addresses = walletAddresses.addresses.map((addr) => addr.address).toSet();
-      return ElectrumTransactionInfo.fromElectrumBundle(tx, walletInfo.type, networkType,
-          addresses: addresses, height: height);
-    } catch (_) {
+      return ElectrumTransactionInfo.fromElectrumBundle(
+          await getTransactionExpanded(hash: hash, height: height), walletInfo.type, network,
+          addresses: myAddresses, height: height);
+    } catch (e) {
+      if (e is FormatException && retryOnFailure == true) {
+        await Future.delayed(const Duration(seconds: 2));
+        return fetchTransactionInfo(hash: hash, height: height, myAddresses: myAddresses);
+      }
       return null;
     }
   }
 
   @override
   Future<Map<String, ElectrumTransactionInfo>> fetchTransactions() async {
-    final addressHashes = <String, BitcoinAddressRecord>{};
-    final normalizedHistories = <Map<String, dynamic>>[];
-    final newTxCounts = <String, int>{};
-
-    walletAddresses.addresses.forEach((addressRecord) {
-      final sh = scriptHash(addressRecord.address, networkType: networkType);
-      addressHashes[sh] = addressRecord;
-      newTxCounts[sh] = 0;
-    });
-
     try {
-      final histories = addressHashes.keys.map((scriptHash) =>
-          electrumClient.getHistory(scriptHash).then((history) => {scriptHash: history}));
-      final historyResults = await Future.wait(histories);
+      final Map<String, ElectrumTransactionInfo> historiesWithDetails = {};
+      final addressesSet = walletAddresses.allAddresses.map((addr) => addr.address).toSet();
+      final currentHeight = await electrumClient.getCurrentBlockChainTip() ?? 0;
 
-      historyResults.forEach((history) {
-        history.entries.forEach((historyItem) {
-          if (historyItem.value.isNotEmpty) {
-            final address = addressHashes[historyItem.key];
-            address?.setAsUsed();
-            newTxCounts[historyItem.key] = historyItem.value.length;
-            normalizedHistories.addAll(historyItem.value);
+      await Future.wait(ADDRESS_TYPES.map((type) {
+        final addressesByType = walletAddresses.allAddresses.where((addr) => addr.type == type);
+
+        return Future.wait(addressesByType.map((addressRecord) async {
+          final history = await _fetchAddressHistory(addressRecord, addressesSet, currentHeight);
+
+          if (history.isNotEmpty) {
+            addressRecord.txCount = history.length;
+            historiesWithDetails.addAll(history);
+
+            final matchedAddresses =
+                addressesByType.where((addr) => addr.isHidden == addressRecord.isHidden);
+
+            final isLastUsedAddress =
+                history.isNotEmpty && addressRecord.address == matchedAddresses.last.address;
+
+            if (isLastUsedAddress) {
+              await walletAddresses.discoverAddresses(
+                  matchedAddresses.toList(),
+                  addressRecord.isHidden,
+                  (address, addressesSet) =>
+                      _fetchAddressHistory(address, addressesSet, currentHeight)
+                          .then((history) => history.isNotEmpty ? address.address : null),
+                  type: type);
+            }
           }
-        });
-      });
-
-      for (var sh in addressHashes.keys) {
-        var balanceData = await electrumClient.getBalance(sh);
-        var addressRecord = addressHashes[sh];
-        if (addressRecord != null) {
-          addressRecord.balance = balanceData['confirmed'] as int? ?? 0;
-        }
-      }
-
-      addressHashes.forEach((sh, addressRecord) {
-        addressRecord.txCount = newTxCounts[sh] ?? 0;
-      });
-
-      final historiesWithDetails = await Future.wait(normalizedHistories.map((transaction) {
-        try {
-          return fetchTransactionInfo(
-              hash: transaction['tx_hash'] as String, height: transaction['height'] as int);
-        } catch (_) {
-          return Future.value(null);
-        }
+        }));
       }));
 
-      return historiesWithDetails.fold<Map<String, ElectrumTransactionInfo>>(
-          <String, ElectrumTransactionInfo>{}, (acc, tx) {
-        if (tx == null) {
-          return acc;
-        }
-        acc[tx.id] = acc[tx.id]?.updated(tx) ?? tx;
-        return acc;
-      });
+      return historiesWithDetails;
+    } catch (e) {
+      print(e.toString());
+      return {};
+    }
+  }
+
+  Future<Map<String, ElectrumTransactionInfo>> _fetchAddressHistory(
+      BitcoinAddressRecord addressRecord, Set<String> addressesSet, int currentHeight) async {
+    try {
+      final Map<String, ElectrumTransactionInfo> historiesWithDetails = {};
+
+      final history = await electrumClient
+          .getHistory(addressRecord.scriptHash ?? addressRecord.updateScriptHash(network));
+
+      if (history.isNotEmpty) {
+        addressRecord.setAsUsed();
+
+        await Future.wait(history.map((transaction) async {
+          final txid = transaction['tx_hash'] as String;
+          final height = transaction['height'] as int;
+          final storedTx = transactionHistory.transactions[txid];
+
+          if (storedTx != null) {
+            if (height > 0) {
+              storedTx.height = height;
+              // the tx's block itself is the first confirmation so add 1
+              storedTx.confirmations = currentHeight - height + 1;
+              storedTx.isPending = storedTx.confirmations == 0;
+            }
+
+            historiesWithDetails[txid] = storedTx;
+          } else {
+            final tx = await fetchTransactionInfo(
+                hash: txid, height: height, myAddresses: addressesSet, retryOnFailure: true);
+
+            if (tx != null) {
+              historiesWithDetails[txid] = tx;
+
+              // Got a new transaction fetched, add it to the transaction history
+              // instead of waiting all to finish, and next time it will be faster
+              transactionHistory.addOne(tx);
+              await transactionHistory.save();
+            }
+          }
+
+          return Future.value(null);
+        }));
+      }
+
+      return historiesWithDetails;
     } catch (e) {
       print(e.toString());
       return {};
@@ -654,10 +757,8 @@ abstract class ElectrumWalletBase
       }
 
       _isTransactionUpdating = true;
-      final transactions = await fetchTransactions();
-      transactionHistory.addMany(transactions);
+      await fetchTransactions();
       walletAddresses.updateReceiveAddresses();
-      await transactionHistory.save();
       _isTransactionUpdating = false;
     } catch (e, stacktrace) {
       print(stacktrace);
@@ -688,11 +789,11 @@ abstract class ElectrumWalletBase
   }
 
   Future<ElectrumBalance> _fetchBalances() async {
-    final addresses = walletAddresses.addresses.toList();
+    final addresses = walletAddresses.allAddresses.toList();
     final balanceFutures = <Future<Map<String, dynamic>>>[];
     for (var i = 0; i < addresses.length; i++) {
       final addressRecord = addresses[i];
-      final sh = scriptHash(addressRecord.address, networkType: networkType);
+      final sh = scriptHash(addressRecord.address, network: network);
       final balanceFuture = electrumClient.getBalance(sh);
       balanceFutures.add(balanceFuture);
     }
@@ -701,6 +802,7 @@ abstract class ElectrumWalletBase
     unspentCoinsInfo.values.forEach((info) {
       unspentCoins.forEach((element) {
         if (element.hash == info.hash &&
+            element.vout == info.vout &&
             info.isFrozen &&
             element.bitcoinAddressRecord.address == info.address &&
             element.value == info.value) {
@@ -738,10 +840,10 @@ abstract class ElectrumWalletBase
   String getChangeAddress() {
     const minCountOfHiddenAddresses = 5;
     final random = Random();
-    var addresses = walletAddresses.addresses.where((addr) => addr.isHidden).toList();
+    var addresses = walletAddresses.allAddresses.where((addr) => addr.isHidden).toList();
 
     if (addresses.length < minCountOfHiddenAddresses) {
-      addresses = walletAddresses.addresses.toList();
+      addresses = walletAddresses.allAddresses.toList();
     }
 
     return addresses[random.nextInt(addresses.length)].address;
@@ -753,9 +855,62 @@ abstract class ElectrumWalletBase
   @override
   String signMessage(String message, {String? address = null}) {
     final index = address != null
-        ? walletAddresses.addresses.firstWhere((element) => element.address == address).index
+        ? walletAddresses.allAddresses.firstWhere((element) => element.address == address).index
         : null;
     final HD = index == null ? hd : hd.derive(index);
     return base64Encode(HD.signMessage(message));
   }
 }
+
+class EstimateTxParams {
+  EstimateTxParams(
+      {required this.amount,
+      required this.feeRate,
+      required this.priority,
+      required this.outputsCount,
+      required this.size});
+
+  final int amount;
+  final int feeRate;
+  final TransactionPriority priority;
+  final int outputsCount;
+  final int size;
+}
+
+class EstimatedTxResult {
+  EstimatedTxResult(
+      {required this.utxos, required this.privateKeys, required this.fee, required this.amount});
+
+  final List<UtxoWithAddress> utxos;
+  final List<ECPrivate> privateKeys;
+  final int fee;
+  final int amount;
+}
+
+BitcoinBaseAddress _addressTypeFromStr(String address, BasedUtxoNetwork network) {
+  if (P2pkhAddress.regex.hasMatch(address)) {
+    return P2pkhAddress.fromAddress(address: address, network: network);
+  } else if (P2shAddress.regex.hasMatch(address)) {
+    return P2shAddress.fromAddress(address: address, network: network);
+  } else if (P2wshAddress.regex.hasMatch(address)) {
+    return P2wshAddress.fromAddress(address: address, network: network);
+  } else if (P2trAddress.regex.hasMatch(address)) {
+    return P2trAddress.fromAddress(address: address, network: network);
+  } else {
+    return P2wpkhAddress.fromAddress(address: address, network: network);
+  }
+}
+
+BitcoinAddressType _getScriptType(BitcoinBaseAddress type) {
+  if (type is P2pkhAddress) {
+    return P2pkhAddressType.p2pkh;
+  } else if (type is P2shAddress) {
+    return P2shAddressType.p2wpkhInP2sh;
+  } else if (type is P2wshAddress) {
+    return SegwitAddresType.p2wsh;
+  } else if (type is P2trAddress) {
+    return SegwitAddresType.p2tr;
+  } else {
+    return SegwitAddresType.p2wpkh;
+  }
+}
diff --git a/cw_bitcoin/lib/electrum_wallet_addresses.dart b/cw_bitcoin/lib/electrum_wallet_addresses.dart
index 850d58f40..5880f5a19 100644
--- a/cw_bitcoin/lib/electrum_wallet_addresses.dart
+++ b/cw_bitcoin/lib/electrum_wallet_addresses.dart
@@ -1,8 +1,8 @@
-import 'package:bitbox/bitbox.dart' as bitbox;
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
+import 'package:bitbox/bitbox.dart' as bitbox;
 import 'package:cw_bitcoin/bitcoin_address_record.dart';
 import 'package:cw_bitcoin/electrum.dart';
-import 'package:cw_bitcoin/script_hash.dart';
 import 'package:cw_core/wallet_addresses.dart';
 import 'package:cw_core/wallet_info.dart';
 import 'package:cw_core/wallet_type.dart';
@@ -12,25 +12,41 @@ part 'electrum_wallet_addresses.g.dart';
 
 class ElectrumWalletAddresses = ElectrumWalletAddressesBase with _$ElectrumWalletAddresses;
 
+const List<BitcoinAddressType> ADDRESS_TYPES = [
+  SegwitAddresType.p2wpkh,
+  P2pkhAddressType.p2pkh,
+  SegwitAddresType.p2tr,
+  SegwitAddresType.p2wsh,
+  P2shAddressType.p2wpkhInP2sh,
+];
+
 abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
-  ElectrumWalletAddressesBase(WalletInfo walletInfo,
-      {required this.mainHd,
-      required this.sideHd,
-      required this.electrumClient,
-      required this.networkType,
-      List<BitcoinAddressRecord>? initialAddresses,
-      int initialRegularAddressIndex = 0,
-      int initialChangeAddressIndex = 0})
-      : addresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? []).toSet()),
+  ElectrumWalletAddressesBase(
+    WalletInfo walletInfo, {
+    required this.mainHd,
+    required this.sideHd,
+    required this.electrumClient,
+    required this.network,
+    List<BitcoinAddressRecord>? initialAddresses,
+    Map<String, int>? initialRegularAddressIndex,
+    Map<String, int>? initialChangeAddressIndex,
+  })  : _addresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? []).toSet()),
+        addressesByReceiveType =
+            ObservableList<BitcoinAddressRecord>.of((<BitcoinAddressRecord>[]).toSet()),
         receiveAddresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? [])
             .where((addressRecord) => !addressRecord.isHidden && !addressRecord.isUsed)
             .toSet()),
         changeAddresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? [])
             .where((addressRecord) => addressRecord.isHidden && !addressRecord.isUsed)
             .toSet()),
-        currentReceiveAddressIndex = initialRegularAddressIndex,
-        currentChangeAddressIndex = initialChangeAddressIndex,
-        super(walletInfo);
+        currentReceiveAddressIndexByType = initialRegularAddressIndex ?? {},
+        currentChangeAddressIndexByType = initialChangeAddressIndex ?? {},
+        _addressPageType = walletInfo.addressPageType != null
+            ? BitcoinAddressType.fromValue(walletInfo.addressPageType!)
+            : SegwitAddresType.p2wpkh,
+        super(walletInfo) {
+    updateAddressesByMatch();
+  }
 
   static const defaultReceiveAddressesCount = 22;
   static const defaultChangeAddressesCount = 17;
@@ -40,37 +56,48 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
 
   static String toLegacy(String address) => bitbox.Address.toLegacyAddress(address);
 
-  final ObservableList<BitcoinAddressRecord> addresses;
+  final ObservableList<BitcoinAddressRecord> _addresses;
+  // Matched by addressPageType
+  late ObservableList<BitcoinAddressRecord> addressesByReceiveType;
   final ObservableList<BitcoinAddressRecord> receiveAddresses;
   final ObservableList<BitcoinAddressRecord> changeAddresses;
   final ElectrumClient electrumClient;
-  final bitcoin.NetworkType networkType;
+  final BasedUtxoNetwork network;
   final bitcoin.HDWallet mainHd;
   final bitcoin.HDWallet sideHd;
 
+  @observable
+  BitcoinAddressType _addressPageType = SegwitAddresType.p2wpkh;
+
+  @computed
+  BitcoinAddressType get addressPageType => _addressPageType;
+
+  @computed
+  List<BitcoinAddressRecord> get allAddresses => _addresses;
+
   @override
   @computed
   String get address {
-    if (isEnabledAutoGenerateSubaddress) {
-      if (receiveAddresses.isEmpty) {
-        final newAddress = generateNewAddress(hd: mainHd).address;
-        return walletInfo.type == WalletType.bitcoinCash ? toCashAddr(newAddress) : newAddress;
-      }
-      final receiveAddress = receiveAddresses.first.address;
+    String receiveAddress;
 
-      return walletInfo.type == WalletType.bitcoinCash
-          ? toCashAddr(receiveAddress)
-          : receiveAddress;
+    final typeMatchingReceiveAddresses = receiveAddresses.where(_isAddressPageTypeMatch);
+
+    if ((isEnabledAutoGenerateSubaddress && receiveAddresses.isEmpty) ||
+        typeMatchingReceiveAddresses.isEmpty) {
+      receiveAddress = generateNewAddress().address;
     } else {
-      final receiveAddress = (receiveAddresses.first.address != addresses.first.address &&
-              previousAddressRecord != null)
-          ? previousAddressRecord!.address
-          : addresses.first.address;
+      final previousAddressMatchesType =
+          previousAddressRecord != null && previousAddressRecord!.type == addressPageType;
 
-      return walletInfo.type == WalletType.bitcoinCash
-          ? toCashAddr(receiveAddress)
-          : receiveAddress;
+      if (previousAddressMatchesType &&
+          typeMatchingReceiveAddresses.first.address != addressesByReceiveType.first.address) {
+        receiveAddress = previousAddressRecord!.address;
+      } else {
+        receiveAddress = typeMatchingReceiveAddresses.first.address;
+      }
     }
+
+    return walletInfo.type == WalletType.bitcoinCash ? toCashAddr(receiveAddress) : receiveAddress;
   }
 
   @observable
@@ -81,7 +108,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
     if (addr.startsWith('bitcoincash:')) {
       addr = toLegacy(addr);
     }
-    final addressRecord = addresses.firstWhere((addressRecord) => addressRecord.address == addr);
+    final addressRecord = _addresses.firstWhere((addressRecord) => addressRecord.address == addr);
 
     previousAddressRecord = addressRecord;
     receiveAddresses.remove(addressRecord);
@@ -89,16 +116,29 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
   }
 
   @override
-  String get primaryAddress => getAddress(index: 0, hd: mainHd);
+  String get primaryAddress => getAddress(index: 0, hd: mainHd, addressType: addressPageType);
 
-  int currentReceiveAddressIndex;
-  int currentChangeAddressIndex;
+  Map<String, int> currentReceiveAddressIndexByType;
+
+  int get currentReceiveAddressIndex =>
+      currentReceiveAddressIndexByType[_addressPageType.toString()] ?? 0;
+
+  void set currentReceiveAddressIndex(int index) =>
+      currentReceiveAddressIndexByType[_addressPageType.toString()] = index;
+
+  Map<String, int> currentChangeAddressIndexByType;
+
+  int get currentChangeAddressIndex =>
+      currentChangeAddressIndexByType[_addressPageType.toString()] ?? 0;
+
+  void set currentChangeAddressIndex(int index) =>
+      currentChangeAddressIndexByType[_addressPageType.toString()] = index;
 
   @observable
   BitcoinAddressRecord? previousAddressRecord;
 
   @computed
-  int get totalCountOfReceiveAddresses => addresses.fold(0, (acc, addressRecord) {
+  int get totalCountOfReceiveAddresses => addressesByReceiveType.fold(0, (acc, addressRecord) {
         if (!addressRecord.isHidden) {
           return acc + 1;
         }
@@ -106,22 +146,21 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
       });
 
   @computed
-  int get totalCountOfChangeAddresses => addresses.fold(0, (acc, addressRecord) {
+  int get totalCountOfChangeAddresses => addressesByReceiveType.fold(0, (acc, addressRecord) {
         if (addressRecord.isHidden) {
           return acc + 1;
         }
         return acc;
       });
 
-  Future<void> discoverAddresses() async {
-    await _discoverAddresses(mainHd, false);
-    await _discoverAddresses(sideHd, true);
-    await updateAddressesInBox();
-  }
-
   @override
   Future<void> init() async {
     await _generateInitialAddresses();
+    await _generateInitialAddresses(type: P2pkhAddressType.p2pkh);
+    await _generateInitialAddresses(type: P2shAddressType.p2wpkhInP2sh);
+    await _generateInitialAddresses(type: SegwitAddresType.p2tr);
+    await _generateInitialAddresses(type: SegwitAddresType.p2wsh);
+    updateAddressesByMatch();
     updateReceiveAddresses();
     updateChangeAddresses();
     await updateAddressesInBox();
@@ -141,10 +180,9 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
 
     if (changeAddresses.isEmpty) {
       final newAddresses = await _createNewAddresses(gap,
-          hd: sideHd,
           startIndex: totalCountOfChangeAddresses > 0 ? totalCountOfChangeAddresses - 1 : 0,
           isHidden: true);
-      _addAddresses(newAddresses);
+      addAddresses(newAddresses);
     }
 
     if (currentChangeAddressIndex >= changeAddresses.length) {
@@ -157,19 +195,26 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
     return address;
   }
 
-  BitcoinAddressRecord generateNewAddress({bitcoin.HDWallet? hd, String? label}) {
-    final isHidden = hd == sideHd;
+  BitcoinAddressRecord generateNewAddress({String label = ''}) {
+    final newAddressIndex = addressesByReceiveType.fold(
+        0, (int acc, addressRecord) => addressRecord.isHidden == false ? acc + 1 : acc);
 
-    final newAddressIndex = addresses.fold(
-        0, (int acc, addressRecord) => isHidden == addressRecord.isHidden ? acc + 1 : acc);
-
-    final address = BitcoinAddressRecord(getAddress(index: newAddressIndex, hd: hd ?? sideHd),
-        index: newAddressIndex, isHidden: isHidden, name: label ?? '');
-    addresses.add(address);
+    final address = BitcoinAddressRecord(
+      getAddress(index: newAddressIndex, hd: mainHd, addressType: addressPageType),
+      index: newAddressIndex,
+      isHidden: false,
+      name: label,
+      type: addressPageType,
+      network: network,
+    );
+    _addresses.add(address);
+    updateAddressesByMatch();
     return address;
   }
 
-  String getAddress({required int index, required bitcoin.HDWallet hd}) => '';
+  String getAddress(
+          {required int index, required bitcoin.HDWallet hd, BitcoinAddressType? addressType}) =>
+      '';
 
   @override
   Future<void> updateAddressesInBox() async {
@@ -187,126 +232,138 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
     if (address.startsWith('bitcoincash:')) {
       address = toLegacy(address);
     }
-    final addressRecord = addresses.firstWhere((addressRecord) => addressRecord.address == address);
+    final addressRecord =
+        _addresses.firstWhere((addressRecord) => addressRecord.address == address);
     addressRecord.setNewName(label);
-    final index = addresses.indexOf(addressRecord);
-    addresses.remove(addressRecord);
-    addresses.insert(index, addressRecord);
+    final index = _addresses.indexOf(addressRecord);
+    _addresses.remove(addressRecord);
+    _addresses.insert(index, addressRecord);
+  }
+
+  @action
+  void updateAddressesByMatch() {
+    addressesByReceiveType.clear();
+    addressesByReceiveType.addAll(_addresses.where(_isAddressPageTypeMatch).toList());
   }
 
   @action
   void updateReceiveAddresses() {
     receiveAddresses.removeRange(0, receiveAddresses.length);
     final newAddresses =
-        addresses.where((addressRecord) => !addressRecord.isHidden && !addressRecord.isUsed);
+        _addresses.where((addressRecord) => !addressRecord.isHidden && !addressRecord.isUsed);
     receiveAddresses.addAll(newAddresses);
   }
 
   @action
   void updateChangeAddresses() {
     changeAddresses.removeRange(0, changeAddresses.length);
-    final newAddresses =
-        addresses.where((addressRecord) => addressRecord.isHidden && !addressRecord.isUsed);
+    final newAddresses = _addresses.where((addressRecord) =>
+        addressRecord.isHidden &&
+        !addressRecord.isUsed &&
+        // TODO: feature to change change address type. For now fixed to p2wpkh, the cheapest type
+        addressRecord.type == SegwitAddresType.p2wpkh);
     changeAddresses.addAll(newAddresses);
   }
 
-  Future<void> _discoverAddresses(bitcoin.HDWallet hd, bool isHidden) async {
-    var hasAddrUse = true;
-    List<BitcoinAddressRecord> addrs;
-
-    if (addresses.isNotEmpty) {
-
-
-      if(!isHidden) {
-        final receiveAddressesList = addresses.where((addr) => !addr.isHidden).toList();
-        validateSideHdAddresses(receiveAddressesList);
-      }
-
-      addrs = addresses.where((addr) => addr.isHidden == isHidden).toList();
-    } else {
-      addrs = await _createNewAddresses(
-          isHidden ? defaultChangeAddressesCount : defaultReceiveAddressesCount,
-          startIndex: 0,
-          hd: hd,
-          isHidden: isHidden);
+  @action
+  Future<void> discoverAddresses(List<BitcoinAddressRecord> addressList, bool isHidden,
+      Future<String?> Function(BitcoinAddressRecord, Set<String>) getAddressHistory,
+      {BitcoinAddressType type = SegwitAddresType.p2wpkh}) async {
+    if (!isHidden) {
+      _validateSideHdAddresses(addressList.toList());
     }
 
-    while (hasAddrUse) {
-      final addr = addrs.last.address;
-      hasAddrUse = await _hasAddressUsed(addr);
+    final newAddresses = await _createNewAddresses(gap,
+        startIndex: addressList.length, isHidden: isHidden, type: type);
+    addAddresses(newAddresses);
 
-      if (!hasAddrUse) {
-        break;
-      }
+    final addressesWithHistory = await Future.wait(newAddresses
+        .map((addr) => getAddressHistory(addr, _addresses.map((e) => e.address).toSet())));
+    final isLastAddressUsed = addressesWithHistory.last == addressList.last.address;
 
-      final start = addrs.length;
-      final count = start + gap;
-      final batch = await _createNewAddresses(count, startIndex: start, hd: hd, isHidden: isHidden);
-      addrs.addAll(batch);
-    }
-
-    if (addresses.length < addrs.length) {
-      _addAddresses(addrs);
+    if (isLastAddressUsed) {
+      discoverAddresses(addressList, isHidden, getAddressHistory, type: type);
     }
   }
 
-  Future<void> _generateInitialAddresses() async {
+  Future<void> _generateInitialAddresses(
+      {BitcoinAddressType type = SegwitAddresType.p2wpkh}) async {
     var countOfReceiveAddresses = 0;
     var countOfHiddenAddresses = 0;
 
-    addresses.forEach((addr) {
-      if (addr.isHidden) {
-        countOfHiddenAddresses += 1;
-        return;
-      }
+    _addresses.forEach((addr) {
+      if (addr.type == type) {
+        if (addr.isHidden) {
+          countOfHiddenAddresses += 1;
+          return;
+        }
 
-      countOfReceiveAddresses += 1;
+        countOfReceiveAddresses += 1;
+      }
     });
 
     if (countOfReceiveAddresses < defaultReceiveAddressesCount) {
       final addressesCount = defaultReceiveAddressesCount - countOfReceiveAddresses;
       final newAddresses = await _createNewAddresses(addressesCount,
-          startIndex: countOfReceiveAddresses, hd: mainHd, isHidden: false);
-      addresses.addAll(newAddresses);
+          startIndex: countOfReceiveAddresses, isHidden: false, type: type);
+      addAddresses(newAddresses);
     }
 
     if (countOfHiddenAddresses < defaultChangeAddressesCount) {
       final addressesCount = defaultChangeAddressesCount - countOfHiddenAddresses;
       final newAddresses = await _createNewAddresses(addressesCount,
-          startIndex: countOfHiddenAddresses, hd: sideHd, isHidden: true);
-      addresses.addAll(newAddresses);
+          startIndex: countOfHiddenAddresses, isHidden: true, type: type);
+      addAddresses(newAddresses);
     }
   }
 
   Future<List<BitcoinAddressRecord>> _createNewAddresses(int count,
-      {required bitcoin.HDWallet hd, int startIndex = 0, bool isHidden = false}) async {
+      {int startIndex = 0, bool isHidden = false, BitcoinAddressType? type}) async {
     final list = <BitcoinAddressRecord>[];
 
     for (var i = startIndex; i < count + startIndex; i++) {
-      final address =
-          BitcoinAddressRecord(getAddress(index: i, hd: hd), index: i, isHidden: isHidden);
+      final address = BitcoinAddressRecord(
+        getAddress(index: i, hd: _getHd(isHidden), addressType: type ?? addressPageType),
+        index: i,
+        isHidden: isHidden,
+        type: type ?? addressPageType,
+        network: network,
+      );
       list.add(address);
     }
 
     return list;
   }
 
-  void _addAddresses(Iterable<BitcoinAddressRecord> addresses) {
-    final addressesSet = this.addresses.toSet();
+  @action
+  void addAddresses(Iterable<BitcoinAddressRecord> addresses) {
+    final addressesSet = this._addresses.toSet();
     addressesSet.addAll(addresses);
-    this.addresses.removeRange(0, this.addresses.length);
-    this.addresses.addAll(addressesSet);
+    this._addresses.clear();
+    this._addresses.addAll(addressesSet);
+    updateAddressesByMatch();
   }
 
-  Future<bool> _hasAddressUsed(String address) async {
-    final sh = scriptHash(address, networkType: networkType);
-    final transactionHistory = await electrumClient.getHistory(sh);
-    return transactionHistory.isNotEmpty;
-  }
-
-  void validateSideHdAddresses(List<BitcoinAddressRecord> addrWithTransactions) {
+  void _validateSideHdAddresses(List<BitcoinAddressRecord> addrWithTransactions) {
     addrWithTransactions.forEach((element) {
-      if (element.address != getAddress(index: element.index, hd: mainHd)) element.isHidden = true;
+      if (element.address !=
+          getAddress(index: element.index, hd: mainHd, addressType: element.type))
+        element.isHidden = true;
     });
   }
+
+  @action
+  Future<void> setAddressType(BitcoinAddressType type) async {
+    _addressPageType = type;
+    updateAddressesByMatch();
+    walletInfo.addressPageType = addressPageType.toString();
+    await walletInfo.save();
+  }
+
+  bool _isAddressPageTypeMatch(BitcoinAddressRecord addressRecord) {
+    return _isAddressByType(addressRecord, addressPageType);
+  }
+
+  bitcoin.HDWallet _getHd(bool isHidden) => isHidden ? sideHd : mainHd;
+  bool _isAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) => addr.type == type;
 }
diff --git a/cw_bitcoin/lib/electrum_wallet_snapshot.dart b/cw_bitcoin/lib/electrum_wallet_snapshot.dart
index 86d3e2fed..98c3753db 100644
--- a/cw_bitcoin/lib/electrum_wallet_snapshot.dart
+++ b/cw_bitcoin/lib/electrum_wallet_snapshot.dart
@@ -1,12 +1,13 @@
 import 'dart:convert';
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:cw_bitcoin/bitcoin_address_record.dart';
 import 'package:cw_bitcoin/electrum_balance.dart';
 import 'package:cw_core/pathForWallet.dart';
 import 'package:cw_core/utils/file.dart';
 import 'package:cw_core/wallet_type.dart';
 
-class ElectrumWallletSnapshot {
-  ElectrumWallletSnapshot({
+class ElectrumWalletSnapshot {
+  ElectrumWalletSnapshot({
     required this.name,
     required this.type,
     required this.password,
@@ -14,19 +15,24 @@ class ElectrumWallletSnapshot {
     required this.addresses,
     required this.balance,
     required this.regularAddressIndex,
-    required this.changeAddressIndex});
+    required this.changeAddressIndex,
+    required this.addressPageType,
+    required this.network,
+  });
 
   final String name;
   final String password;
   final WalletType type;
+  final String addressPageType;
+  final BasedUtxoNetwork network;
 
   String mnemonic;
   List<BitcoinAddressRecord> addresses;
   ElectrumBalance balance;
-  int regularAddressIndex;
-  int changeAddressIndex;
+  Map<String, int> regularAddressIndex;
+  Map<String, int> changeAddressIndex;
 
-  static Future<ElectrumWallletSnapshot> load(String name, WalletType type, String password) async {
+  static Future<ElectrumWalletSnapshot> load(String name, WalletType type, String password, BasedUtxoNetwork? network) async {
     final path = await pathForWallet(name: name, type: type);
     final jsonSource = await read(path: path, password: password);
     final data = json.decode(jsonSource) as Map;
@@ -34,26 +40,39 @@ class ElectrumWallletSnapshot {
     final mnemonic = data['mnemonic'] as String;
     final addresses = addressesTmp
         .whereType<String>()
-        .map((addr) => BitcoinAddressRecord.fromJSON(addr))
+        .map((addr) => BitcoinAddressRecord.fromJSON(addr, network))
         .toList();
     final balance = ElectrumBalance.fromJSON(data['balance'] as String) ??
         ElectrumBalance(confirmed: 0, unconfirmed: 0, frozen: 0);
-    var regularAddressIndex = 0;
-    var changeAddressIndex = 0;
+    var regularAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0};
+    var changeAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0};
 
     try {
-      regularAddressIndex = int.parse(data['account_index'] as String? ?? '0');
-      changeAddressIndex = int.parse(data['change_address_index'] as String? ?? '0');
-    } catch (_) {}
+      regularAddressIndexByType = {
+        SegwitAddresType.p2wpkh.toString(): int.parse(data['account_index'] as String? ?? '0')
+      };
+      changeAddressIndexByType = {
+        SegwitAddresType.p2wpkh.toString():
+            int.parse(data['change_address_index'] as String? ?? '0')
+      };
+    } catch (_) {
+      try {
+        regularAddressIndexByType = data["account_index"] as Map<String, int>? ?? {};
+        changeAddressIndexByType = data["change_address_index"] as Map<String, int>? ?? {};
+      } catch (_) {}
+    }
 
-    return ElectrumWallletSnapshot(
+    return ElectrumWalletSnapshot(
       name: name,
       type: type,
       password: password,
       mnemonic: mnemonic,
       addresses: addresses,
       balance: balance,
-      regularAddressIndex: regularAddressIndex,
-      changeAddressIndex: changeAddressIndex);
+      regularAddressIndex: regularAddressIndexByType,
+      changeAddressIndex: changeAddressIndexByType,
+      addressPageType: data['address_page_type'] as String? ?? SegwitAddresType.p2wpkh.toString(),
+      network: data['network_type'] == 'testnet' ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet,
+    );
   }
 }
diff --git a/cw_bitcoin/lib/litecoin_wallet.dart b/cw_bitcoin/lib/litecoin_wallet.dart
index 222e95acc..d2379d5a5 100644
--- a/cw_bitcoin/lib/litecoin_wallet.dart
+++ b/cw_bitcoin/lib/litecoin_wallet.dart
@@ -1,3 +1,4 @@
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
 import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
 import 'package:cw_core/crypto_currency.dart';
@@ -20,17 +21,18 @@ part 'litecoin_wallet.g.dart';
 class LitecoinWallet = LitecoinWalletBase with _$LitecoinWallet;
 
 abstract class LitecoinWalletBase extends ElectrumWallet with Store {
-  LitecoinWalletBase(
-      {required String mnemonic,
-      required String password,
-      required WalletInfo walletInfo,
-      required Box<UnspentCoinsInfo> unspentCoinsInfo,
-      required Uint8List seedBytes,
-      List<BitcoinAddressRecord>? initialAddresses,
-      ElectrumBalance? initialBalance,
-      int initialRegularAddressIndex = 0,
-      int initialChangeAddressIndex = 0})
-      : super(
+  LitecoinWalletBase({
+    required String mnemonic,
+    required String password,
+    required WalletInfo walletInfo,
+    required Box<UnspentCoinsInfo> unspentCoinsInfo,
+    required Uint8List seedBytes,
+    String? addressPageType,
+    List<BitcoinAddressRecord>? initialAddresses,
+    ElectrumBalance? initialBalance,
+    Map<String, int>? initialRegularAddressIndex,
+    Map<String, int>? initialChangeAddressIndex,
+  }) : super(
             mnemonic: mnemonic,
             password: password,
             walletInfo: walletInfo,
@@ -41,41 +43,42 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
             seedBytes: seedBytes,
             currency: CryptoCurrency.ltc) {
     walletAddresses = LitecoinWalletAddresses(
-        walletInfo,
-        electrumClient: electrumClient,
-        initialAddresses: initialAddresses,
-        initialRegularAddressIndex: initialRegularAddressIndex,
-        initialChangeAddressIndex: initialChangeAddressIndex,
-        mainHd: hd,
-        sideHd: bitcoin.HDWallet
-                .fromSeed(seedBytes, network: networkType)
-                .derivePath("m/0'/1"),
-        networkType: networkType,);
+      walletInfo,
+      electrumClient: electrumClient,
+      initialAddresses: initialAddresses,
+      initialRegularAddressIndex: initialRegularAddressIndex,
+      initialChangeAddressIndex: initialChangeAddressIndex,
+      mainHd: hd,
+      sideHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/1"),
+      network: network,
+    );
     autorun((_) {
       this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
     });
   }
 
-  static Future<LitecoinWallet> create({
-    required String mnemonic,
-    required String password,
-    required WalletInfo walletInfo,
-    required Box<UnspentCoinsInfo> unspentCoinsInfo,
-    List<BitcoinAddressRecord>? initialAddresses,
-    ElectrumBalance? initialBalance,
-    int initialRegularAddressIndex = 0,
-    int initialChangeAddressIndex = 0
-  }) async {
+  static Future<LitecoinWallet> create(
+      {required String mnemonic,
+      required String password,
+      required WalletInfo walletInfo,
+      required Box<UnspentCoinsInfo> unspentCoinsInfo,
+      String? addressPageType,
+      List<BitcoinAddressRecord>? initialAddresses,
+      ElectrumBalance? initialBalance,
+      Map<String, int>? initialRegularAddressIndex,
+      Map<String, int>? initialChangeAddressIndex}) async {
     return LitecoinWallet(
-        mnemonic: mnemonic,
-        password: password,
-        walletInfo: walletInfo,
-        unspentCoinsInfo: unspentCoinsInfo,
-        initialAddresses: initialAddresses,
-        initialBalance: initialBalance,
-        seedBytes: await mnemonicToSeedBytes(mnemonic),
-        initialRegularAddressIndex: initialRegularAddressIndex,
-        initialChangeAddressIndex: initialChangeAddressIndex);
+      mnemonic: mnemonic,
+      password: password,
+      walletInfo: walletInfo,
+      unspentCoinsInfo: unspentCoinsInfo,
+      initialAddresses: initialAddresses,
+      initialBalance: initialBalance,
+      seedBytes: await mnemonicToSeedBytes(mnemonic),
+      initialRegularAddressIndex: initialRegularAddressIndex,
+      initialChangeAddressIndex: initialChangeAddressIndex,
+      addressPageType: addressPageType,
+    );
   }
 
   static Future<LitecoinWallet> open({
@@ -84,17 +87,20 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
     required Box<UnspentCoinsInfo> unspentCoinsInfo,
     required String password,
   }) async {
-    final snp = await ElectrumWallletSnapshot.load (name, walletInfo.type, password);
+    final snp =
+        await ElectrumWalletSnapshot.load(name, walletInfo.type, password, LitecoinNetwork.mainnet);
     return LitecoinWallet(
-        mnemonic: snp.mnemonic,
-        password: password,
-        walletInfo: walletInfo,
-        unspentCoinsInfo: unspentCoinsInfo,
-        initialAddresses: snp.addresses,
-        initialBalance: snp.balance,
-        seedBytes: await mnemonicToSeedBytes(snp.mnemonic),
-        initialRegularAddressIndex: snp.regularAddressIndex,
-        initialChangeAddressIndex: snp.changeAddressIndex);
+      mnemonic: snp.mnemonic,
+      password: password,
+      walletInfo: walletInfo,
+      unspentCoinsInfo: unspentCoinsInfo,
+      initialAddresses: snp.addresses,
+      initialBalance: snp.balance,
+      seedBytes: await mnemonicToSeedBytes(snp.mnemonic),
+      initialRegularAddressIndex: snp.regularAddressIndex,
+      initialChangeAddressIndex: snp.changeAddressIndex,
+      addressPageType: snp.addressPageType,
+    );
   }
 
   @override
diff --git a/cw_bitcoin/lib/litecoin_wallet_addresses.dart b/cw_bitcoin/lib/litecoin_wallet_addresses.dart
index a317fa9f2..993d17933 100644
--- a/cw_bitcoin/lib/litecoin_wallet_addresses.dart
+++ b/cw_bitcoin/lib/litecoin_wallet_addresses.dart
@@ -1,39 +1,28 @@
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
-import 'package:cw_bitcoin/electrum.dart';
 import 'package:cw_bitcoin/utils.dart';
-import 'package:cw_bitcoin/bitcoin_address_record.dart';
 import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
 import 'package:cw_core/wallet_info.dart';
-import 'package:flutter/foundation.dart';
 import 'package:mobx/mobx.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(
-      WalletInfo walletInfo,
-      {required bitcoin.HDWallet mainHd,
-        required bitcoin.HDWallet sideHd,
-        required bitcoin.NetworkType networkType,
-        required ElectrumClient electrumClient,
-        List<BitcoinAddressRecord>? initialAddresses,
-        int initialRegularAddressIndex = 0,
-        int initialChangeAddressIndex = 0})
-      : super(
-      walletInfo,
-      initialAddresses: initialAddresses,
-      initialRegularAddressIndex: initialRegularAddressIndex,
-      initialChangeAddressIndex: initialChangeAddressIndex,
-      mainHd: mainHd,
-      sideHd: sideHd,
-      electrumClient: electrumClient,
-      networkType: networkType);
+    WalletInfo walletInfo, {
+    required super.mainHd,
+    required super.sideHd,
+    required super.network,
+    required super.electrumClient,
+    super.initialAddresses,
+    super.initialRegularAddressIndex,
+    super.initialChangeAddressIndex,
+  }) : super(walletInfo);
 
   @override
-  String getAddress({required int index, required bitcoin.HDWallet hd}) =>
-      generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
-}
\ No newline at end of file
+  String getAddress(
+          {required int index, required bitcoin.HDWallet hd, BitcoinAddressType? addressType}) =>
+      generateP2WPKHAddress(hd: hd, index: index, network: network);
+}
diff --git a/cw_bitcoin/lib/litecoin_wallet_service.dart b/cw_bitcoin/lib/litecoin_wallet_service.dart
index 69d1dfc7e..3d7462fa1 100644
--- a/cw_bitcoin/lib/litecoin_wallet_service.dart
+++ b/cw_bitcoin/lib/litecoin_wallet_service.dart
@@ -25,7 +25,7 @@ class LitecoinWalletService extends WalletService<
   WalletType getType() => WalletType.litecoin;
 
   @override
-  Future<LitecoinWallet> create(BitcoinNewWalletCredentials credentials) async {
+  Future<LitecoinWallet> create(BitcoinNewWalletCredentials credentials, {bool? isTestnet}) async {
     final wallet = await LitecoinWalletBase.create(
         mnemonic: await generateMnemonic(),
         password: credentials.password!,
@@ -94,12 +94,12 @@ class LitecoinWalletService extends WalletService<
 
   @override
   Future<LitecoinWallet> restoreFromKeys(
-          BitcoinRestoreWalletFromWIFCredentials credentials) async =>
+          BitcoinRestoreWalletFromWIFCredentials credentials, {bool? isTestnet}) async =>
       throw UnimplementedError();
 
   @override
   Future<LitecoinWallet> restoreFromSeed(
-      BitcoinRestoreWalletFromSeedCredentials credentials) async {
+      BitcoinRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async {
     if (!validateMnemonic(credentials.mnemonic)) {
       throw BitcoinMnemonicIsIncorrectException();
     }
diff --git a/cw_bitcoin/lib/pending_bitcoin_transaction.dart b/cw_bitcoin/lib/pending_bitcoin_transaction.dart
index e2dc10bfb..fa413febd 100644
--- a/cw_bitcoin/lib/pending_bitcoin_transaction.dart
+++ b/cw_bitcoin/lib/pending_bitcoin_transaction.dart
@@ -1,5 +1,5 @@
 import 'package:cw_bitcoin/bitcoin_commit_transaction_exception.dart';
-import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:cw_core/pending_transaction.dart';
 import 'package:cw_bitcoin/electrum.dart';
 import 'package:cw_bitcoin/bitcoin_amount_format.dart';
@@ -9,22 +9,21 @@ import 'package:cw_core/wallet_type.dart';
 
 class PendingBitcoinTransaction with PendingTransaction {
   PendingBitcoinTransaction(this._tx, this.type,
-      {required this.electrumClient,
-      required this.amount,
-      required this.fee})
+      {required this.electrumClient, required this.amount, required this.fee, this.network})
       : _listeners = <void Function(ElectrumTransactionInfo transaction)>[];
 
   final WalletType type;
-  final bitcoin.Transaction _tx;
+  final BtcTransaction _tx;
   final ElectrumClient electrumClient;
   final int amount;
   final int fee;
+  final BasedUtxoNetwork? network;
 
   @override
-  String get id => _tx.getId();
+  String get id => _tx.txId();
 
   @override
-  String get hex => _tx.toHex();
+  String get hex => _tx.serialize();
 
   @override
   String get amountFormatted => bitcoinAmountToString(amount: amount);
@@ -36,18 +35,16 @@ class PendingBitcoinTransaction with PendingTransaction {
 
   @override
   Future<void> commit() async {
-    final result =
-      await electrumClient.broadcastTransaction(transactionRaw: _tx.toHex());
+    final result = await electrumClient.broadcastTransaction(transactionRaw: hex, network: network);
 
     if (result.isEmpty) {
       throw BitcoinCommitTransactionException();
     }
 
-    _listeners?.forEach((listener) => listener(transactionInfo()));
+    _listeners.forEach((listener) => listener(transactionInfo()));
   }
 
-  void addListener(
-          void Function(ElectrumTransactionInfo transaction) listener) =>
+  void addListener(void Function(ElectrumTransactionInfo transaction) listener) =>
       _listeners.add(listener);
 
   ElectrumTransactionInfo transactionInfo() => ElectrumTransactionInfo(type,
diff --git a/cw_bitcoin/lib/script_hash.dart b/cw_bitcoin/lib/script_hash.dart
index 76a1bfcf0..620d3d28a 100644
--- a/cw_bitcoin/lib/script_hash.dart
+++ b/cw_bitcoin/lib/script_hash.dart
@@ -1,9 +1,8 @@
-import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:crypto/crypto.dart';
 
-String scriptHash(String address, {required bitcoin.NetworkType networkType}) {
-  final outputScript =
-      bitcoin.Address.addressToOutputScript(address, networkType);
+String scriptHash(String address, {required BasedUtxoNetwork network}) {
+  final outputScript = addressToOutputScript(address: address, network: network);
   final parts = sha256.convert(outputScript).toString().split('');
   var res = '';
 
diff --git a/cw_bitcoin/lib/utils.dart b/cw_bitcoin/lib/utils.dart
index 0d5a413b3..b156ccba3 100644
--- a/cw_bitcoin/lib/utils.dart
+++ b/cw_bitcoin/lib/utils.dart
@@ -1,55 +1,33 @@
 import 'dart:typed_data';
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:flutter/foundation.dart';
 import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
 import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
 import 'package:hex/hex.dart';
 
-bitcoin.PaymentData generatePaymentData(
-        {required bitcoin.HDWallet hd, required int index}) =>
-    PaymentData(
-        pubkey: Uint8List.fromList(HEX.decode(hd.derive(index).pubKey!)));
+bitcoin.PaymentData generatePaymentData({required bitcoin.HDWallet hd, required int index}) =>
+    PaymentData(pubkey: Uint8List.fromList(HEX.decode(hd.derive(index).pubKey!)));
 
-bitcoin.ECPair generateKeyPair(
-        {required bitcoin.HDWallet hd,
-        required int index,
-        required bitcoin.NetworkType network}) =>
-    bitcoin.ECPair.fromWIF(hd.derive(index).wif!, network: network);
+ECPrivate generateECPrivate(
+        {required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) =>
+    ECPrivate.fromWif(hd.derive(index).wif!, netVersion: network.wifNetVer);
 
 String generateP2WPKHAddress(
-        {required bitcoin.HDWallet hd,
-        required int index,
-        required bitcoin.NetworkType networkType}) =>
-    bitcoin
-        .P2WPKH(
-            data: PaymentData(
-                pubkey:
-                    Uint8List.fromList(HEX.decode(hd.derive(index).pubKey!))),
-            network: networkType)
-        .data
-        .address!;
+        {required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) =>
+    ECPublic.fromHex(hd.derive(index).pubKey!).toP2wpkhAddress().toAddress(network);
 
-String generateP2WPKHAddressByPath(
-        {required bitcoin.HDWallet hd,
-        required String path,
-        required bitcoin.NetworkType networkType}) =>
-    bitcoin
-        .P2WPKH(
-            data: PaymentData(
-                pubkey:
-                    Uint8List.fromList(HEX.decode(hd.derivePath(path).pubKey!))),
-            network: networkType)
-        .data
-        .address!;
+String generateP2SHAddress(
+        {required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) =>
+    ECPublic.fromHex(hd.derive(index).pubKey!).toP2wpkhInP2sh().toAddress(network);
+
+String generateP2WSHAddress(
+        {required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) =>
+    ECPublic.fromHex(hd.derive(index).pubKey!).toP2wshAddress().toAddress(network);
 
 String generateP2PKHAddress(
-        {required bitcoin.HDWallet hd,
-        required int index,
-        required bitcoin.NetworkType networkType}) =>
-    bitcoin
-        .P2PKH(
-            data: PaymentData(
-                pubkey:
-                    Uint8List.fromList(HEX.decode(hd.derive(index).pubKey!))),
-            network: networkType)
-        .data
-        .address!;
+        {required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) =>
+    ECPublic.fromHex(hd.derive(index).pubKey!).toP2pkhAddress().toAddress(network);
+
+String generateP2TRAddress(
+        {required bitcoin.HDWallet hd, required int index, required BasedUtxoNetwork network}) =>
+    ECPublic.fromHex(hd.derive(index).pubKey!).toTaprootAddress().toAddress(network);
diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock
index 3344cb807..25e6f269d 100644
--- a/cw_bitcoin/pubspec.lock
+++ b/cw_bitcoin/pubspec.lock
@@ -21,18 +21,18 @@ packages:
     dependency: transitive
     description:
       name: args
-      sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611"
+      sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.2"
+    version: "2.4.2"
   asn1lib:
     dependency: transitive
     description:
       name: asn1lib
-      sha256: ab96a1cb3beeccf8145c52e449233fe68364c9641623acd3adad66f8184f1039
+      sha256: c9c85fedbe2188b95133cbe960e16f5f448860f7133330e272edbbca5893ddc6
       url: "https://pub.dev"
     source: hosted
-    version: "1.4.0"
+    version: "1.5.2"
   async:
     dependency: transitive
     description:
@@ -75,6 +75,15 @@ packages:
       url: "https://github.com/cake-tech/bitbox-flutter.git"
     source: git
     version: "1.0.1"
+  bitcoin_base:
+    dependency: "direct main"
+    description:
+      path: "."
+      ref: cake-update-v1
+      resolved-ref: "9611e9db77e92a8434e918cdfb620068f6fcb1aa"
+      url: "https://github.com/cake-tech/bitcoin_base.git"
+    source: git
+    version: "4.0.0"
   bitcoin_flutter:
     dependency: "direct main"
     description:
@@ -84,6 +93,14 @@ packages:
       url: "https://github.com/cake-tech/bitcoin_flutter.git"
     source: git
     version: "2.1.0"
+  blockchain_utils:
+    dependency: "direct main"
+    description:
+      name: blockchain_utils
+      sha256: "9701dfaa74caad4daae1785f1ec4445cf7fb94e45620bc3a4aca1b9b281dc6c9"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.6.0"
   boolean_selector:
     dependency: transitive
     description:
@@ -104,10 +121,10 @@ packages:
     dependency: transitive
     description:
       name: build
-      sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777"
+      sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.1"
+    version: "2.4.1"
   build_config:
     dependency: transitive
     description:
@@ -120,10 +137,10 @@ packages:
     dependency: transitive
     description:
       name: build_daemon
-      sha256: "6bc5544ea6ce4428266e7ea680e945c68806c4aae2da0eb5e9ccf38df8d6acbf"
+      sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1"
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.0"
+    version: "4.0.1"
   build_resolvers:
     dependency: "direct dev"
     description:
@@ -136,18 +153,18 @@ packages:
     dependency: "direct dev"
     description:
       name: build_runner
-      sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727
+      sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21"
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.3"
+    version: "2.4.8"
   build_runner_core:
     dependency: transitive
     description:
       name: build_runner_core
-      sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292"
+      sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41"
       url: "https://pub.dev"
     source: hosted
-    version: "7.2.7"
+    version: "7.2.10"
   built_collection:
     dependency: transitive
     description:
@@ -160,10 +177,10 @@ packages:
     dependency: transitive
     description:
       name: built_value
-      sha256: "169565c8ad06adb760c3645bf71f00bff161b00002cace266cad42c5d22a7725"
+      sha256: a3ec2e0f967bc47f69f95009bb93db936288d61d5343b9436e378b28a2f830c6
       url: "https://pub.dev"
     source: hosted
-    version: "8.4.3"
+    version: "8.9.0"
   characters:
     dependency: transitive
     description:
@@ -176,10 +193,10 @@ packages:
     dependency: transitive
     description:
       name: checked_yaml
-      sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311"
+      sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.2"
+    version: "2.0.3"
   clock:
     dependency: transitive
     description:
@@ -192,10 +209,10 @@ packages:
     dependency: transitive
     description:
       name: code_builder
-      sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe"
+      sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
       url: "https://pub.dev"
     source: hosted
-    version: "4.4.0"
+    version: "4.10.0"
   collection:
     dependency: transitive
     description:
@@ -216,18 +233,18 @@ packages:
     dependency: transitive
     description:
       name: crypto
-      sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
+      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.2"
+    version: "3.0.3"
   cryptography:
     dependency: "direct main"
     description:
       name: cryptography
-      sha256: e0e37f79665cd5c86e8897f9abe1accfe813c0cc5299dab22256e22fddc1fef8
+      sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.5"
+    version: "2.5.0"
   cw_core:
     dependency: "direct main"
     description:
@@ -247,10 +264,10 @@ packages:
     dependency: transitive
     description:
       name: encrypt
-      sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb"
+      sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
       url: "https://pub.dev"
     source: hosted
-    version: "5.0.1"
+    version: "5.0.3"
   fake_async:
     dependency: transitive
     description:
@@ -263,10 +280,10 @@ packages:
     dependency: transitive
     description:
       name: ffi
-      sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978
+      sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.1"
+    version: "2.1.0"
   file:
     dependency: transitive
     description:
@@ -292,10 +309,10 @@ packages:
     dependency: "direct main"
     description:
       name: flutter_mobx
-      sha256: "0da4add0016387a7bf309a0d0c41d36c6b3ae25ed7a176409267f166509e723e"
+      sha256: "4a5d062ff85ed3759f4aac6410ff0ffae32e324b2e71ca722ae1b37b32e865f4"
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.6+5"
+    version: "2.2.0+2"
   flutter_test:
     dependency: "direct dev"
     description: flutter
@@ -313,18 +330,18 @@ packages:
     dependency: transitive
     description:
       name: glob
-      sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
+      sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.1"
+    version: "2.1.2"
   graphs:
     dependency: transitive
     description:
       name: graphs
-      sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2
+      sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.0"
+    version: "2.3.1"
   hex:
     dependency: transitive
     description:
@@ -401,18 +418,18 @@ packages:
     dependency: transitive
     description:
       name: json_annotation
-      sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317
+      sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
       url: "https://pub.dev"
     source: hosted
-    version: "4.8.0"
+    version: "4.8.1"
   logging:
     dependency: transitive
     description:
       name: logging
-      sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
+      sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
       url: "https://pub.dev"
     source: hosted
-    version: "1.1.1"
+    version: "1.2.0"
   matcher:
     dependency: transitive
     description:
@@ -449,18 +466,26 @@ packages:
     dependency: "direct main"
     description:
       name: mobx
-      sha256: f1862bd92c6a903fab67338f27e2f731117c3cb9ea37cee1a487f9e4e0de314a
+      sha256: "74ee54012dc7c1b3276eaa960a600a7418ef5f9997565deb8fca1fd88fb36b78"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.3+1"
+    version: "2.3.0+1"
   mobx_codegen:
     dependency: "direct dev"
     description:
       name: mobx_codegen
-      sha256: "86122e410d8ea24dda0c69adb5c2a6ccadd5ce02ad46e144764e0d0184a06181"
+      sha256: d4beb9cea4b7b014321235f8fdc7c2193ee0fe1d1198e9da7403f8bc85c4407c
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.1"
+    version: "2.3.0"
+  nested:
+    dependency: transitive
+    description:
+      name: nested
+      sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.0"
   package_config:
     dependency: transitive
     description:
@@ -481,26 +506,26 @@ packages:
     dependency: "direct main"
     description:
       name: path_provider
-      sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
+      sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.1"
+    version: "2.1.2"
   path_provider_android:
     dependency: transitive
     description:
       name: path_provider_android
-      sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
+      sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668"
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.1"
+    version: "2.2.2"
   path_provider_foundation:
     dependency: transitive
     description:
       name: path_provider_foundation
-      sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
+      sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.1"
+    version: "2.3.2"
   path_provider_linux:
     dependency: transitive
     description:
@@ -513,10 +538,10 @@ packages:
     dependency: transitive
     description:
       name: path_provider_platform_interface
-      sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
+      sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.1"
+    version: "2.1.2"
   path_provider_windows:
     dependency: transitive
     description:
@@ -529,26 +554,26 @@ packages:
     dependency: transitive
     description:
       name: platform
-      sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
+      sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.0"
+    version: "3.1.4"
   plugin_platform_interface:
     dependency: transitive
     description:
       name: plugin_platform_interface
-      sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a
+      sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.3"
+    version: "2.1.8"
   pointycastle:
     dependency: transitive
     description:
       name: pointycastle
-      sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346
+      sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
       url: "https://pub.dev"
     source: hosted
-    version: "3.6.2"
+    version: "3.7.4"
   pool:
     dependency: transitive
     description:
@@ -557,30 +582,30 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.5.1"
-  process:
+  provider:
     dependency: transitive
     description:
-      name: process
-      sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
+      name: provider
+      sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096"
       url: "https://pub.dev"
     source: hosted
-    version: "4.2.4"
+    version: "6.1.1"
   pub_semver:
     dependency: transitive
     description:
       name: pub_semver
-      sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17"
+      sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.3"
+    version: "2.1.4"
   pubspec_parse:
     dependency: transitive
     description:
       name: pubspec_parse
-      sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a"
+      sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367
       url: "https://pub.dev"
     source: hosted
-    version: "1.2.1"
+    version: "1.2.3"
   rxdart:
     dependency: "direct main"
     description:
@@ -593,18 +618,18 @@ packages:
     dependency: transitive
     description:
       name: shelf
-      sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c
+      sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
       url: "https://pub.dev"
     source: hosted
-    version: "1.4.0"
+    version: "1.4.1"
   shelf_web_socket:
     dependency: transitive
     description:
       name: shelf_web_socket
-      sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8
+      sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
       url: "https://pub.dev"
     source: hosted
-    version: "1.0.3"
+    version: "1.0.4"
   sky_engine:
     dependency: transitive
     description: flutter
@@ -702,10 +727,10 @@ packages:
     dependency: transitive
     description:
       name: typed_data
-      sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
+      sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
       url: "https://pub.dev"
     source: hosted
-    version: "1.3.1"
+    version: "1.3.2"
   unorm_dart:
     dependency: "direct main"
     description:
@@ -726,42 +751,42 @@ packages:
     dependency: transitive
     description:
       name: watcher
-      sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
+      sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
       url: "https://pub.dev"
     source: hosted
-    version: "1.0.2"
+    version: "1.1.0"
   web_socket_channel:
     dependency: transitive
     description:
       name: web_socket_channel
-      sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b
+      sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.0"
+    version: "2.4.0"
   win32:
     dependency: transitive
     description:
       name: win32
-      sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
+      sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3"
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.3"
+    version: "5.0.9"
   xdg_directories:
     dependency: transitive
     description:
       name: xdg_directories
-      sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86
+      sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
       url: "https://pub.dev"
     source: hosted
-    version: "0.2.0+3"
+    version: "1.0.4"
   yaml:
     dependency: transitive
     description:
       name: yaml
-      sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370"
+      sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.1"
+    version: "3.1.2"
 sdks:
   dart: ">=3.0.0 <4.0.0"
-  flutter: ">=3.7.0"
+  flutter: ">=3.10.0"
diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml
index 7b3943814..82128448e 100644
--- a/cw_bitcoin/pubspec.yaml
+++ b/cw_bitcoin/pubspec.yaml
@@ -34,6 +34,11 @@ dependencies:
   rxdart: ^0.27.5
   unorm_dart: ^0.2.0
   cryptography: ^2.0.5
+  bitcoin_base:
+    git:
+      url: https://github.com/cake-tech/bitcoin_base.git
+      ref: cake-update-v1
+  blockchain_utils: ^1.6.0
 
 dev_dependencies:
   flutter_test:
diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart
index 1b87e2231..3c40cf9e9 100644
--- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart
+++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart
@@ -28,17 +28,18 @@ part 'bitcoin_cash_wallet.g.dart';
 class BitcoinCashWallet = BitcoinCashWalletBase with _$BitcoinCashWallet;
 
 abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
-  BitcoinCashWalletBase(
-      {required String mnemonic,
-      required String password,
-      required WalletInfo walletInfo,
-      required Box<UnspentCoinsInfo> unspentCoinsInfo,
-      required Uint8List seedBytes,
-      List<BitcoinAddressRecord>? initialAddresses,
-      ElectrumBalance? initialBalance,
-      int initialRegularAddressIndex = 0,
-      int initialChangeAddressIndex = 0})
-      : super(
+  BitcoinCashWalletBase({
+    required String mnemonic,
+    required String password,
+    required WalletInfo walletInfo,
+    required Box<UnspentCoinsInfo> unspentCoinsInfo,
+    required Uint8List seedBytes,
+    String? addressPageType,
+    List<BitcoinAddressRecord>? initialAddresses,
+    ElectrumBalance? initialBalance,
+    Map<String, int>? initialRegularAddressIndex,
+    Map<String, int>? initialChangeAddressIndex,
+  }) : super(
             mnemonic: mnemonic,
             password: password,
             walletInfo: walletInfo,
@@ -48,40 +49,43 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
             initialBalance: initialBalance,
             seedBytes: seedBytes,
             currency: CryptoCurrency.bch) {
-    walletAddresses = BitcoinCashWalletAddresses(walletInfo,
-        electrumClient: electrumClient,
-        initialAddresses: initialAddresses,
-        initialRegularAddressIndex: initialRegularAddressIndex,
-        initialChangeAddressIndex: initialChangeAddressIndex,
-        mainHd: hd,
-        sideHd: bitcoin.HDWallet.fromSeed(seedBytes)
-            .derivePath("m/44'/145'/0'/1"),
-        networkType: networkType);
+    walletAddresses = BitcoinCashWalletAddresses(
+      walletInfo,
+      electrumClient: electrumClient,
+      initialAddresses: initialAddresses,
+      initialRegularAddressIndex: initialRegularAddressIndex,
+      initialChangeAddressIndex: initialChangeAddressIndex,
+      mainHd: hd,
+      sideHd: bitcoin.HDWallet.fromSeed(seedBytes).derivePath("m/44'/145'/0'/1"),
+      network: network,
+    );
     autorun((_) {
       this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
     });
   }
 
-
   static Future<BitcoinCashWallet> create(
       {required String mnemonic,
       required String password,
       required WalletInfo walletInfo,
       required Box<UnspentCoinsInfo> unspentCoinsInfo,
+      String? addressPageType,
       List<BitcoinAddressRecord>? initialAddresses,
       ElectrumBalance? initialBalance,
-      int initialRegularAddressIndex = 0,
-      int initialChangeAddressIndex = 0}) async {
+      Map<String, int>? initialRegularAddressIndex,
+      Map<String, int>? initialChangeAddressIndex}) async {
     return BitcoinCashWallet(
-        mnemonic: mnemonic,
-        password: password,
-        walletInfo: walletInfo,
-        unspentCoinsInfo: unspentCoinsInfo,
-        initialAddresses: initialAddresses,
-        initialBalance: initialBalance,
-        seedBytes: await Mnemonic.toSeed(mnemonic),
-        initialRegularAddressIndex: initialRegularAddressIndex,
-        initialChangeAddressIndex: initialChangeAddressIndex);
+      mnemonic: mnemonic,
+      password: password,
+      walletInfo: walletInfo,
+      unspentCoinsInfo: unspentCoinsInfo,
+      initialAddresses: initialAddresses,
+      initialBalance: initialBalance,
+      seedBytes: await Mnemonic.toSeed(mnemonic),
+      initialRegularAddressIndex: initialRegularAddressIndex,
+      initialChangeAddressIndex: initialChangeAddressIndex,
+      addressPageType: addressPageType,
+    );
   }
 
   static Future<BitcoinCashWallet> open({
@@ -90,17 +94,20 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
     required Box<UnspentCoinsInfo> unspentCoinsInfo,
     required String password,
   }) async {
-    final snp = await ElectrumWallletSnapshot.load(name, walletInfo.type, password);
+    final snp = await ElectrumWalletSnapshot.load(
+        name, walletInfo.type, password, BitcoinCashNetwork.mainnet);
     return BitcoinCashWallet(
-        mnemonic: snp.mnemonic,
-        password: password,
-        walletInfo: walletInfo,
-        unspentCoinsInfo: unspentCoinsInfo,
-        initialAddresses: snp.addresses,
-        initialBalance: snp.balance,
-        seedBytes: await Mnemonic.toSeed(snp.mnemonic),
-        initialRegularAddressIndex: snp.regularAddressIndex,
-        initialChangeAddressIndex: snp.changeAddressIndex);
+      mnemonic: snp.mnemonic,
+      password: password,
+      walletInfo: walletInfo,
+      unspentCoinsInfo: unspentCoinsInfo,
+      initialAddresses: snp.addresses,
+      initialBalance: snp.balance,
+      seedBytes: await Mnemonic.toSeed(snp.mnemonic),
+      initialRegularAddressIndex: snp.regularAddressIndex,
+      initialChangeAddressIndex: snp.changeAddressIndex,
+      addressPageType: snp.addressPageType,
+    );
   }
 
   @override
@@ -270,20 +277,18 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
         electrumClient: electrumClient, amount: amount, fee: fee);
   }
 
-  bitbox.ECPair generateKeyPair(
-          {required bitcoin.HDWallet hd,
-          required int index}) =>
+  bitbox.ECPair generateKeyPair({required bitcoin.HDWallet hd, required int index}) =>
       bitbox.ECPair.fromWIF(hd.derive(index).wif!);
 
   @override
-  int feeAmountForPriority(
-          BitcoinTransactionPriority priority, int inputsCount, int outputsCount) =>
+  int feeAmountForPriority(BitcoinTransactionPriority priority, int inputsCount, int outputsCount,
+          {int? size}) =>
       feeRate(priority) * bitbox.BitcoinCash.getByteCount(inputsCount, outputsCount);
 
-  int feeAmountWithFeeRate(int feeRate, int inputsCount, int outputsCount) =>
+  int feeAmountWithFeeRate(int feeRate, int inputsCount, int outputsCount, {int? size}) =>
       feeRate * bitbox.BitcoinCash.getByteCount(inputsCount, outputsCount);
 
-  int calculateEstimatedFeeWithFeeRate(int feeRate, int? amount, {int? outputsCount}) {
+  int calculateEstimatedFeeWithFeeRate(int feeRate, int? amount, {int? outputsCount, int? size}) {
     int inputsCount = 0;
     int totalValue = 0;
 
@@ -323,9 +328,10 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
   @override
   String signMessage(String message, {String? address = null}) {
     final index = address != null
-        ? walletAddresses.addresses
+        ? walletAddresses.allAddresses
             .firstWhere((element) => element.address == AddressUtils.toLegacyAddress(address))
-            .index : null;
+            .index
+        : null;
     final HD = index == null ? hd : hd.derive(index);
     return base64Encode(HD.signMessage(message));
   }
diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart
index 1709c4d8f..8291ce2a5 100644
--- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart
+++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart
@@ -1,6 +1,5 @@
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
-import 'package:cw_bitcoin/bitcoin_address_record.dart';
-import 'package:cw_bitcoin/electrum.dart';
 import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
 import 'package:cw_bitcoin/utils.dart';
 import 'package:cw_core/wallet_info.dart';
@@ -11,24 +10,19 @@ part 'bitcoin_cash_wallet_addresses.g.dart';
 class BitcoinCashWalletAddresses = BitcoinCashWalletAddressesBase with _$BitcoinCashWalletAddresses;
 
 abstract class BitcoinCashWalletAddressesBase extends ElectrumWalletAddresses with Store {
-  BitcoinCashWalletAddressesBase(WalletInfo walletInfo,
-      {required bitcoin.HDWallet mainHd,
-      required bitcoin.HDWallet sideHd,
-      required bitcoin.NetworkType networkType,
-      required ElectrumClient electrumClient,
-      List<BitcoinAddressRecord>? initialAddresses,
-      int initialRegularAddressIndex = 0,
-      int initialChangeAddressIndex = 0})
-      : super(walletInfo,
-            initialAddresses: initialAddresses,
-            initialRegularAddressIndex: initialRegularAddressIndex,
-            initialChangeAddressIndex: initialChangeAddressIndex,
-            mainHd: mainHd,
-            sideHd: sideHd,
-            electrumClient: electrumClient,
-            networkType: networkType);
+  BitcoinCashWalletAddressesBase(
+    WalletInfo walletInfo, {
+    required super.mainHd,
+    required super.sideHd,
+    required super.network,
+    required super.electrumClient,
+    super.initialAddresses,
+    super.initialRegularAddressIndex,
+    super.initialChangeAddressIndex,
+  }) : super(walletInfo);
 
   @override
-  String getAddress({required int index, required bitcoin.HDWallet hd}) =>
-      generateP2PKHAddress(hd: hd, index: index, networkType: networkType);
+  String getAddress(
+          {required int index, required bitcoin.HDWallet hd, BitcoinAddressType? addressType}) =>
+      generateP2PKHAddress(hd: hd, index: index, network: network);
 }
diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart
index f66e38ca7..df8e841f8 100644
--- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart
+++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart
@@ -2,10 +2,7 @@ import 'dart:io';
 
 import 'package:bip39/bip39.dart';
 import 'package:cw_bitcoin_cash/cw_bitcoin_cash.dart';
-import 'package:cw_core/balance.dart';
 import 'package:cw_core/pathForWallet.dart';
-import 'package:cw_core/transaction_history.dart';
-import 'package:cw_core/transaction_info.dart';
 import 'package:cw_core/unspent_coins_info.dart';
 import 'package:cw_core/wallet_base.dart';
 import 'package:cw_core/wallet_info.dart';
@@ -15,8 +12,7 @@ import 'package:collection/collection.dart';
 import 'package:hive/hive.dart';
 
 class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredentials,
-    BitcoinCashRestoreWalletFromSeedCredentials,
-    BitcoinCashRestoreWalletFromWIFCredentials> {
+    BitcoinCashRestoreWalletFromSeedCredentials, BitcoinCashRestoreWalletFromWIFCredentials> {
   BitcoinCashWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
 
   final Box<WalletInfo> walletInfoSource;
@@ -30,13 +26,9 @@ class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredent
       File(await pathForWallet(name: name, type: getType())).existsSync();
 
   @override
-  Future<BitcoinCashWallet> create(
-      credentials) async {
-    final strength = (credentials.seedPhraseLength == 12)
-        ? 128
-        : (credentials.seedPhraseLength == 24)
-        ? 256
-        : 128;
+  Future<BitcoinCashWallet> create(credentials, {bool? isTestnet}) async {
+    final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
+
     final wallet = await BitcoinCashWalletBase.create(
         mnemonic: await Mnemonic.generate(strength: strength),
         password: credentials.password!,
@@ -49,21 +41,25 @@ class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredent
 
   @override
   Future<BitcoinCashWallet> openWallet(String name, String password) async {
-    final walletInfo = walletInfoSource.values.firstWhereOrNull(
-            (info) => info.id == WalletBase.idFor(name, getType()))!;
+    final walletInfo = walletInfoSource.values
+        .firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
 
     try {
       final wallet = await BitcoinCashWalletBase.open(
-          password: password, name: name, walletInfo: walletInfo,
+          password: password,
+          name: name,
+          walletInfo: walletInfo,
           unspentCoinsInfo: unspentCoinsInfoSource);
       await wallet.init();
       saveBackup(name);
       return wallet;
-    } catch(_) {
+    } catch (_) {
       await restoreWalletFilesFromBackup(name);
       final wallet = await BitcoinCashWalletBase.open(
-      password: password, name: name, walletInfo: walletInfo,
-      unspentCoinsInfo: unspentCoinsInfoSource);
+          password: password,
+          name: name,
+          walletInfo: walletInfo,
+          unspentCoinsInfo: unspentCoinsInfoSource);
       await wallet.init();
       return wallet;
     }
@@ -71,17 +67,16 @@ class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredent
 
   @override
   Future<void> remove(String wallet) async {
-    File(await pathForWalletDir(name: wallet, type: getType()))
-        .delete(recursive: true);
-    final walletInfo = walletInfoSource.values.firstWhereOrNull(
-            (info) => info.id == WalletBase.idFor(wallet, getType()))!;
+    File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
+    final walletInfo = walletInfoSource.values
+        .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
     await walletInfoSource.delete(walletInfo.key);
   }
 
   @override
   Future<void> rename(String currentName, String password, String newName) async {
-    final currentWalletInfo = walletInfoSource.values.firstWhereOrNull(
-            (info) => info.id == WalletBase.idFor(currentName, getType()))!;
+    final currentWalletInfo = walletInfoSource.values
+        .firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
     final currentWallet = await BitcoinCashWalletBase.open(
         password: password,
         name: currentName,
@@ -99,15 +94,14 @@ class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredent
   }
 
   @override
-  Future<BitcoinCashWallet>
-  restoreFromKeys(credentials) {
+  Future<BitcoinCashWallet> restoreFromKeys(credentials, {bool? isTestnet}) {
     // TODO: implement restoreFromKeys
     throw UnimplementedError('restoreFromKeys() is not implemented');
   }
 
   @override
-  Future<BitcoinCashWallet> restoreFromSeed(
-      BitcoinCashRestoreWalletFromSeedCredentials credentials) async {
+  Future<BitcoinCashWallet> restoreFromSeed(BitcoinCashRestoreWalletFromSeedCredentials credentials,
+      {bool? isTestnet}) async {
     if (!validateMnemonic(credentials.mnemonic)) {
       throw BitcoinCashMnemonicIsIncorrectException();
     }
diff --git a/cw_bitcoin_cash/pubspec.yaml b/cw_bitcoin_cash/pubspec.yaml
index 44e5eecbb..e9459d27c 100644
--- a/cw_bitcoin_cash/pubspec.yaml
+++ b/cw_bitcoin_cash/pubspec.yaml
@@ -29,7 +29,10 @@ dependencies:
     git:
       url: https://github.com/cake-tech/bitbox-flutter.git
       ref: master
-  bitcoin_base: ^3.0.1
+  bitcoin_base:
+    git:
+      url: https://github.com/cake-tech/bitcoin_base.git
+      ref: cake-update-v1
 
 
 
diff --git a/cw_core/lib/enumerate.dart b/cw_core/lib/enumerate.dart
new file mode 100644
index 000000000..d92347e91
--- /dev/null
+++ b/cw_core/lib/enumerate.dart
@@ -0,0 +1,13 @@
+abstract class Enumerate {
+  String get value;
+
+  @override
+  operator ==(other) {
+    if (identical(other, this)) return true;
+    if (other is! Enumerate) return false;
+    return other.runtimeType == runtimeType && value == other.value;
+  }
+
+  @override
+  int get hashCode => value.hashCode;
+}
diff --git a/cw_core/lib/receive_page_option.dart b/cw_core/lib/receive_page_option.dart
new file mode 100644
index 000000000..786d07bc5
--- /dev/null
+++ b/cw_core/lib/receive_page_option.dart
@@ -0,0 +1,21 @@
+import 'package:cw_core/enumerate.dart';
+
+class ReceivePageOption implements Enumerate {
+  static const mainnet = ReceivePageOption._('mainnet');
+  static const anonPayInvoice = ReceivePageOption._('anonPayInvoice');
+  static const anonPayDonationLink = ReceivePageOption._('anonPayDonationLink');
+
+  const ReceivePageOption._(this.value);
+
+  final String value;
+
+  String toString() {
+    return value;
+  }
+}
+
+const ReceivePageOptions = [
+  ReceivePageOption.mainnet,
+  ReceivePageOption.anonPayInvoice,
+  ReceivePageOption.anonPayDonationLink
+];
diff --git a/cw_core/lib/wallet_base.dart b/cw_core/lib/wallet_base.dart
index 09b423c14..49f1bdc94 100644
--- a/cw_core/lib/wallet_base.dart
+++ b/cw_core/lib/wallet_base.dart
@@ -88,4 +88,6 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
   Future<void> renameWalletFiles(String newWalletName);
 
   String signMessage(String message, {String? address = null}) => throw UnimplementedError();
+
+  bool? isTestnet;
 }
diff --git a/cw_core/lib/wallet_info.dart b/cw_core/lib/wallet_info.dart
index c4ccea00a..2a44175a7 100644
--- a/cw_core/lib/wallet_info.dart
+++ b/cw_core/lib/wallet_info.dart
@@ -148,6 +148,12 @@ class WalletInfo extends HiveObject {
   @HiveField(17)
   String? derivationPath;
 
+  @HiveField(18)
+  String? addressPageType;
+
+  @HiveField(19)
+  String? network;
+
   String get yatLastUsedAddress => yatLastUsedAddressRaw ?? '';
 
   set yatLastUsedAddress(String address) {
diff --git a/cw_core/lib/wallet_service.dart b/cw_core/lib/wallet_service.dart
index 3b4908386..22981b9db 100644
--- a/cw_core/lib/wallet_service.dart
+++ b/cw_core/lib/wallet_service.dart
@@ -9,11 +9,11 @@ abstract class WalletService<N extends WalletCredentials, RFS extends WalletCred
     RFK extends WalletCredentials> {
   WalletType getType();
 
-  Future<WalletBase> create(N credentials);
+  Future<WalletBase> create(N credentials, {bool? isTestnet});
 
-  Future<WalletBase> restoreFromSeed(RFS credentials);
+  Future<WalletBase> restoreFromSeed(RFS credentials, {bool? isTestnet});
 
-  Future<WalletBase> restoreFromKeys(RFK credentials);
+  Future<WalletBase> restoreFromKeys(RFK credentials, {bool? isTestnet});
 
   Future<WalletBase> openWallet(String name, String password);
 
diff --git a/cw_core/pubspec.lock b/cw_core/pubspec.lock
index aacbd9ddd..678e57b54 100644
--- a/cw_core/pubspec.lock
+++ b/cw_core/pubspec.lock
@@ -5,34 +5,34 @@ packages:
     dependency: transitive
     description:
       name: _fe_analyzer_shared
-      sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8"
+      sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051
       url: "https://pub.dev"
     source: hosted
-    version: "47.0.0"
+    version: "64.0.0"
   analyzer:
     dependency: transitive
     description:
       name: analyzer
-      sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80"
+      sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893"
       url: "https://pub.dev"
     source: hosted
-    version: "4.7.0"
+    version: "6.2.0"
   args:
     dependency: transitive
     description:
       name: args
-      sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611"
+      sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.2"
+    version: "2.4.2"
   asn1lib:
     dependency: transitive
     description:
       name: asn1lib
-      sha256: ab96a1cb3beeccf8145c52e449233fe68364c9641623acd3adad66f8184f1039
+      sha256: "21afe4333076c02877d14f4a89df111e658a6d466cbfc802eb705eb91bd5adfd"
       url: "https://pub.dev"
     source: hosted
-    version: "1.4.0"
+    version: "1.5.0"
   async:
     dependency: transitive
     description:
@@ -53,10 +53,10 @@ packages:
     dependency: transitive
     description:
       name: build
-      sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777"
+      sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.1"
+    version: "2.4.1"
   build_config:
     dependency: transitive
     description:
@@ -69,34 +69,34 @@ packages:
     dependency: transitive
     description:
       name: build_daemon
-      sha256: "6bc5544ea6ce4428266e7ea680e945c68806c4aae2da0eb5e9ccf38df8d6acbf"
+      sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1"
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.0"
+    version: "4.0.1"
   build_resolvers:
     dependency: "direct dev"
     description:
       name: build_resolvers
-      sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6"
+      sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.10"
+    version: "2.4.2"
   build_runner:
     dependency: "direct dev"
     description:
       name: build_runner
-      sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727
+      sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21"
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.3"
+    version: "2.4.8"
   build_runner_core:
     dependency: transitive
     description:
       name: build_runner_core
-      sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292"
+      sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185
       url: "https://pub.dev"
     source: hosted
-    version: "7.2.7"
+    version: "7.2.11"
   built_collection:
     dependency: transitive
     description:
@@ -109,10 +109,10 @@ packages:
     dependency: transitive
     description:
       name: built_value
-      sha256: "169565c8ad06adb760c3645bf71f00bff161b00002cace266cad42c5d22a7725"
+      sha256: c9aabae0718ec394e5bc3c7272e6bb0dc0b32201a08fe185ec1d8401d3e39309
       url: "https://pub.dev"
     source: hosted
-    version: "8.4.3"
+    version: "8.8.1"
   characters:
     dependency: transitive
     description:
@@ -125,10 +125,10 @@ packages:
     dependency: transitive
     description:
       name: checked_yaml
-      sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311"
+      sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.2"
+    version: "2.0.3"
   clock:
     dependency: transitive
     description:
@@ -141,10 +141,10 @@ packages:
     dependency: transitive
     description:
       name: code_builder
-      sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe"
+      sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
       url: "https://pub.dev"
     source: hosted
-    version: "4.4.0"
+    version: "4.10.0"
   collection:
     dependency: transitive
     description:
@@ -165,26 +165,26 @@ packages:
     dependency: transitive
     description:
       name: crypto
-      sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
+      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.2"
+    version: "3.0.3"
   dart_style:
     dependency: transitive
     description:
       name: dart_style
-      sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4"
+      sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368"
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.4"
+    version: "2.3.4"
   encrypt:
     dependency: "direct main"
     description:
       name: encrypt
-      sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb"
+      sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
       url: "https://pub.dev"
     source: hosted
-    version: "5.0.1"
+    version: "5.0.3"
   fake_async:
     dependency: transitive
     description:
@@ -197,10 +197,10 @@ packages:
     dependency: transitive
     description:
       name: ffi
-      sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978
+      sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.1"
+    version: "2.1.0"
   file:
     dependency: "direct main"
     description:
@@ -226,10 +226,10 @@ packages:
     dependency: "direct main"
     description:
       name: flutter_mobx
-      sha256: "0da4add0016387a7bf309a0d0c41d36c6b3ae25ed7a176409267f166509e723e"
+      sha256: "4a5d062ff85ed3759f4aac6410ff0ffae32e324b2e71ca722ae1b37b32e865f4"
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.6+5"
+    version: "2.2.0+2"
   flutter_test:
     dependency: "direct dev"
     description: flutter
@@ -247,18 +247,18 @@ packages:
     dependency: transitive
     description:
       name: glob
-      sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
+      sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.1"
+    version: "2.1.2"
   graphs:
     dependency: transitive
     description:
       name: graphs
-      sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2
+      sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.0"
+    version: "2.3.1"
   hive:
     dependency: transitive
     description:
@@ -327,18 +327,18 @@ packages:
     dependency: transitive
     description:
       name: json_annotation
-      sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317
+      sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
       url: "https://pub.dev"
     source: hosted
-    version: "4.8.0"
+    version: "4.8.1"
   logging:
     dependency: transitive
     description:
       name: logging
-      sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
+      sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
       url: "https://pub.dev"
     source: hosted
-    version: "1.1.1"
+    version: "1.2.0"
   matcher:
     dependency: transitive
     description:
@@ -375,18 +375,26 @@ packages:
     dependency: "direct main"
     description:
       name: mobx
-      sha256: f1862bd92c6a903fab67338f27e2f731117c3cb9ea37cee1a487f9e4e0de314a
+      sha256: "74ee54012dc7c1b3276eaa960a600a7418ef5f9997565deb8fca1fd88fb36b78"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.3+1"
+    version: "2.3.0+1"
   mobx_codegen:
     dependency: "direct dev"
     description:
       name: mobx_codegen
-      sha256: "86122e410d8ea24dda0c69adb5c2a6ccadd5ce02ad46e144764e0d0184a06181"
+      sha256: b26c7f9c20b38f0ea572c1ed3f29d8e027cb265538bbd1aed3ec198642cfca42
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.1"
+    version: "2.6.0+1"
+  nested:
+    dependency: transitive
+    description:
+      name: nested
+      sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.0"
   package_config:
     dependency: transitive
     description:
@@ -407,26 +415,26 @@ packages:
     dependency: "direct main"
     description:
       name: path_provider
-      sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
+      sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.1"
+    version: "2.1.2"
   path_provider_android:
     dependency: transitive
     description:
       name: path_provider_android
-      sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
+      sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668"
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.1"
+    version: "2.2.2"
   path_provider_foundation:
     dependency: transitive
     description:
       name: path_provider_foundation
-      sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
+      sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.1"
+    version: "2.3.2"
   path_provider_linux:
     dependency: transitive
     description:
@@ -439,10 +447,10 @@ packages:
     dependency: transitive
     description:
       name: path_provider_platform_interface
-      sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
+      sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.1"
+    version: "2.1.2"
   path_provider_windows:
     dependency: transitive
     description:
@@ -455,26 +463,26 @@ packages:
     dependency: transitive
     description:
       name: platform
-      sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
+      sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.0"
+    version: "3.1.4"
   plugin_platform_interface:
     dependency: transitive
     description:
       name: plugin_platform_interface
-      sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a
+      sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.3"
+    version: "2.1.8"
   pointycastle:
     dependency: transitive
     description:
       name: pointycastle
-      sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346
+      sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
       url: "https://pub.dev"
     source: hosted
-    version: "3.6.2"
+    version: "3.7.4"
   pool:
     dependency: transitive
     description:
@@ -483,46 +491,46 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.5.1"
-  process:
+  provider:
     dependency: transitive
     description:
-      name: process
-      sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
+      name: provider
+      sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096"
       url: "https://pub.dev"
     source: hosted
-    version: "4.2.4"
+    version: "6.1.1"
   pub_semver:
     dependency: transitive
     description:
       name: pub_semver
-      sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17"
+      sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.3"
+    version: "2.1.4"
   pubspec_parse:
     dependency: transitive
     description:
       name: pubspec_parse
-      sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a"
+      sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367
       url: "https://pub.dev"
     source: hosted
-    version: "1.2.1"
+    version: "1.2.3"
   shelf:
     dependency: transitive
     description:
       name: shelf
-      sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c
+      sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
       url: "https://pub.dev"
     source: hosted
-    version: "1.4.0"
+    version: "1.4.1"
   shelf_web_socket:
     dependency: transitive
     description:
       name: shelf_web_socket
-      sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8
+      sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
       url: "https://pub.dev"
     source: hosted
-    version: "1.0.3"
+    version: "1.0.4"
   sky_engine:
     dependency: transitive
     description: flutter
@@ -540,18 +548,18 @@ packages:
     dependency: transitive
     description:
       name: source_gen
-      sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d"
+      sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
       url: "https://pub.dev"
     source: hosted
-    version: "1.2.6"
+    version: "1.5.0"
   source_helper:
     dependency: transitive
     description:
       name: source_helper
-      sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f"
+      sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd"
       url: "https://pub.dev"
     source: hosted
-    version: "1.3.3"
+    version: "1.3.4"
   source_span:
     dependency: transitive
     description:
@@ -620,10 +628,10 @@ packages:
     dependency: transitive
     description:
       name: typed_data
-      sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
+      sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
       url: "https://pub.dev"
     source: hosted
-    version: "1.3.1"
+    version: "1.3.2"
   vector_math:
     dependency: transitive
     description:
@@ -636,42 +644,42 @@ packages:
     dependency: transitive
     description:
       name: watcher
-      sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
+      sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
       url: "https://pub.dev"
     source: hosted
-    version: "1.0.2"
+    version: "1.1.0"
   web_socket_channel:
     dependency: transitive
     description:
       name: web_socket_channel
-      sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b
+      sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.0"
+    version: "2.4.0"
   win32:
     dependency: transitive
     description:
       name: win32
-      sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
+      sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3"
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.3"
+    version: "5.0.9"
   xdg_directories:
     dependency: transitive
     description:
       name: xdg_directories
-      sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86
+      sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
       url: "https://pub.dev"
     source: hosted
-    version: "0.2.0+3"
+    version: "1.0.4"
   yaml:
     dependency: transitive
     description:
       name: yaml
-      sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370"
+      sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.1"
+    version: "3.1.2"
 sdks:
   dart: ">=3.0.0 <4.0.0"
-  flutter: ">=3.7.0"
+  flutter: ">=3.10.0"
diff --git a/cw_ethereum/lib/ethereum_wallet_service.dart b/cw_ethereum/lib/ethereum_wallet_service.dart
index 5e8c22718..53c8bfea9 100644
--- a/cw_ethereum/lib/ethereum_wallet_service.dart
+++ b/cw_ethereum/lib/ethereum_wallet_service.dart
@@ -16,7 +16,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
   WalletType getType() => WalletType.ethereum;
 
   @override
-  Future<EthereumWallet> create(EVMChainNewWalletCredentials credentials) async {
+  Future<EthereumWallet> create(EVMChainNewWalletCredentials credentials, {bool? isTestnet}) async {
     final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
 
     final mnemonic = bip39.generateMnemonic(strength: strength);
@@ -52,7 +52,6 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
       saveBackup(name);
       return wallet;
     } catch (_) {
-      
       await restoreWalletFilesFromBackup(name);
 
       final wallet = await EthereumWallet.open(
@@ -84,7 +83,8 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
   }
 
   @override
-  Future<EthereumWallet> restoreFromKeys(EVMChainRestoreWalletFromPrivateKey credentials) async {
+  Future<EthereumWallet> restoreFromKeys(EVMChainRestoreWalletFromPrivateKey credentials,
+      {bool? isTestnet}) async {
     final wallet = EthereumWallet(
       password: credentials.password!,
       privateKey: credentials.privateKey,
@@ -100,8 +100,8 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
   }
 
   @override
-  Future<EthereumWallet> restoreFromSeed(
-      EVMChainRestoreWalletFromSeedCredentials credentials) async {
+  Future<EthereumWallet> restoreFromSeed(EVMChainRestoreWalletFromSeedCredentials credentials,
+      {bool? isTestnet}) async {
     if (!bip39.validateMnemonic(credentials.mnemonic)) {
       throw EthereumMnemonicIsIncorrectException();
     }
diff --git a/cw_evm/lib/evm_chain_wallet_service.dart b/cw_evm/lib/evm_chain_wallet_service.dart
index 988a38684..d77a3a81a 100644
--- a/cw_evm/lib/evm_chain_wallet_service.dart
+++ b/cw_evm/lib/evm_chain_wallet_service.dart
@@ -22,7 +22,7 @@ abstract class EVMChainWalletService<T extends EVMChainWallet> extends WalletSer
   WalletType getType();
 
   @override
-  Future<T> create(EVMChainNewWalletCredentials credentials);
+  Future<T> create(EVMChainNewWalletCredentials credentials, {bool? isTestnet});
 
   @override
   Future<T> openWallet(String name, String password);
@@ -31,10 +31,10 @@ abstract class EVMChainWalletService<T extends EVMChainWallet> extends WalletSer
   Future<void> rename(String currentName, String password, String newName);
 
   @override
-  Future<T> restoreFromKeys(EVMChainRestoreWalletFromPrivateKey credentials);
+  Future<T> restoreFromKeys(EVMChainRestoreWalletFromPrivateKey credentials, {bool? isTestnet});
 
   @override
-  Future<T> restoreFromSeed(EVMChainRestoreWalletFromSeedCredentials credentials);
+  Future<T> restoreFromSeed(EVMChainRestoreWalletFromSeedCredentials credentials, {bool? isTestnet});
 
   @override
   Future<bool> isWalletExit(String name) async =>
diff --git a/cw_haven/lib/haven_wallet_service.dart b/cw_haven/lib/haven_wallet_service.dart
index dd7713e08..d4808c2d6 100644
--- a/cw_haven/lib/haven_wallet_service.dart
+++ b/cw_haven/lib/haven_wallet_service.dart
@@ -68,7 +68,7 @@ class HavenWalletService extends WalletService<
   WalletType getType() => WalletType.haven;
 
   @override
-  Future<HavenWallet> create(HavenNewWalletCredentials credentials) async {
+  Future<HavenWallet> create(HavenNewWalletCredentials credentials, {bool? isTestnet}) async {
     try {
       final path = await pathForWallet(name: credentials.name, type: getType());
       await haven_wallet_manager.createWallet(
@@ -174,7 +174,7 @@ class HavenWalletService extends WalletService<
 
   @override
   Future<HavenWallet> restoreFromKeys(
-      HavenRestoreWalletFromKeysCredentials credentials) async {
+      HavenRestoreWalletFromKeysCredentials credentials, {bool? isTestnet}) async {
     try {
       final path = await pathForWallet(name: credentials.name, type: getType());
       await haven_wallet_manager.restoreFromKeys(
@@ -198,7 +198,7 @@ class HavenWalletService extends WalletService<
 
   @override
   Future<HavenWallet> restoreFromSeed(
-      HavenRestoreWalletFromSeedCredentials credentials) async {
+      HavenRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async {
     try {
       final path = await pathForWallet(name: credentials.name, type: getType());
       await haven_wallet_manager.restoreFromSeed(
diff --git a/cw_monero/lib/monero_wallet_service.dart b/cw_monero/lib/monero_wallet_service.dart
index 3dea7fc0e..1f33dbb3d 100644
--- a/cw_monero/lib/monero_wallet_service.dart
+++ b/cw_monero/lib/monero_wallet_service.dart
@@ -68,7 +68,7 @@ class MoneroWalletService extends WalletService<MoneroNewWalletCredentials,
   WalletType getType() => WalletType.monero;
 
   @override
-  Future<MoneroWallet> create(MoneroNewWalletCredentials credentials) async {
+  Future<MoneroWallet> create(MoneroNewWalletCredentials credentials, {bool? isTestnet}) async {
     try {
       final path = await pathForWallet(name: credentials.name, type: getType());
 
@@ -203,7 +203,8 @@ class MoneroWalletService extends WalletService<MoneroNewWalletCredentials,
   }
 
   @override
-  Future<MoneroWallet> restoreFromKeys(MoneroRestoreWalletFromKeysCredentials credentials) async {
+  Future<MoneroWallet> restoreFromKeys(MoneroRestoreWalletFromKeysCredentials credentials,
+      {bool? isTestnet}) async {
     try {
       final path = await pathForWallet(name: credentials.name, type: getType());
       await monero_wallet_manager.restoreFromKeys(
@@ -227,7 +228,8 @@ class MoneroWalletService extends WalletService<MoneroNewWalletCredentials,
   }
 
   @override
-  Future<MoneroWallet> restoreFromSeed(MoneroRestoreWalletFromSeedCredentials credentials) async {
+  Future<MoneroWallet> restoreFromSeed(MoneroRestoreWalletFromSeedCredentials credentials,
+      {bool? isTestnet}) async {
     // Restore from Polyseed
     if (Polyseed.isValidSeed(credentials.mnemonic)) {
       return restoreFromPolyseed(credentials);
diff --git a/cw_nano/lib/nano_wallet_service.dart b/cw_nano/lib/nano_wallet_service.dart
index a76f0393d..7ab502d49 100644
--- a/cw_nano/lib/nano_wallet_service.dart
+++ b/cw_nano/lib/nano_wallet_service.dart
@@ -26,7 +26,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
   WalletType getType() => WalletType.nano;
 
   @override
-  Future<WalletBase> create(NanoNewWalletCredentials credentials) async {
+  Future<WalletBase> create(NanoNewWalletCredentials credentials, {bool? isTestnet}) async {
     // nano standard:
     DerivationType derivationType = DerivationType.nano;
     String seedKey = NanoSeeds.generateSeed();
@@ -79,7 +79,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
   }
 
   @override
-  Future<NanoWallet> restoreFromKeys(NanoRestoreWalletFromKeysCredentials credentials) async {
+  Future<NanoWallet> restoreFromKeys(NanoRestoreWalletFromKeysCredentials credentials, {bool? isTestnet}) async {
     if (credentials.seedKey.contains(' ')) {
       throw Exception("Invalid key!");
     } else {
@@ -113,7 +113,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
   }
 
   @override
-  Future<NanoWallet> restoreFromSeed(NanoRestoreWalletFromSeedCredentials credentials) async {
+  Future<NanoWallet> restoreFromSeed(NanoRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async {
     if (credentials.mnemonic.contains(' ')) {
       if (!bip39.validateMnemonic(credentials.mnemonic)) {
         throw nm.NanoMnemonicIsIncorrectException();
diff --git a/cw_polygon/lib/polygon_wallet_service.dart b/cw_polygon/lib/polygon_wallet_service.dart
index 0199a1552..59e14abbf 100644
--- a/cw_polygon/lib/polygon_wallet_service.dart
+++ b/cw_polygon/lib/polygon_wallet_service.dart
@@ -19,7 +19,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
   WalletType getType() => WalletType.polygon;
 
   @override
-  Future<PolygonWallet> create(EVMChainNewWalletCredentials credentials) async {
+  Future<PolygonWallet> create(EVMChainNewWalletCredentials credentials, {bool? isTestnet}) async {
     final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
 
     final mnemonic = bip39.generateMnemonic(strength: strength);
@@ -62,7 +62,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
         password: password,
         walletInfo: walletInfo,
       );
-      
+
       await wallet.init();
       await wallet.save();
       return wallet;
@@ -70,8 +70,8 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
   }
 
   @override
-  Future<PolygonWallet> restoreFromKeys(EVMChainRestoreWalletFromPrivateKey credentials) async {
-
+  Future<PolygonWallet> restoreFromKeys(EVMChainRestoreWalletFromPrivateKey credentials,
+      {bool? isTestnet}) async {
     final wallet = PolygonWallet(
       password: credentials.password!,
       privateKey: credentials.privateKey,
@@ -87,8 +87,8 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
   }
 
   @override
-  Future<PolygonWallet> restoreFromSeed(
-      EVMChainRestoreWalletFromSeedCredentials credentials) async {
+  Future<PolygonWallet> restoreFromSeed(EVMChainRestoreWalletFromSeedCredentials credentials,
+      {bool? isTestnet}) async {
     if (!bip39.validateMnemonic(credentials.mnemonic)) {
       throw PolygonMnemonicIsIncorrectException();
     }
diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart
index 688825013..f9c20d45e 100644
--- a/lib/bitcoin/cw_bitcoin.dart
+++ b/lib/bitcoin/cw_bitcoin.dart
@@ -1,181 +1,191 @@
 part of 'bitcoin.dart';
 
 class CWBitcoin extends Bitcoin {
-	@override
-	TransactionPriority getMediumTransactionPriority() => BitcoinTransactionPriority.medium;	
-
-	@override
-	WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({
-    required String name,
-    required String mnemonic,
-    required String password})
-		=> BitcoinRestoreWalletFromSeedCredentials(name: name, mnemonic: mnemonic, password: password);
-	
-	@override
-	WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({
-    required String name,
-    required String password,
-    required String wif,
-    WalletInfo? walletInfo})
-		=> BitcoinRestoreWalletFromWIFCredentials(name: name, password: password, wif: wif, walletInfo: walletInfo);
-	
-	@override
-	WalletCredentials createBitcoinNewWalletCredentials({
-    required String name,
-    WalletInfo? walletInfo})
-		=> BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo);
-
-	@override
-	List<String> getWordList() => wordlist;
-
-	@override
-	Map<String, String> getWalletKeys(Object wallet) {
-		final bitcoinWallet = wallet as ElectrumWallet;
-		final keys = bitcoinWallet.keys;
-		
-		return <String, String>{
-			'wif': keys.wif,
-			'privateKey': keys.privateKey,
-			'publicKey': keys.publicKey	
-		};
-	}
-	
-	@override
-	List<TransactionPriority> getTransactionPriorities() 
-		=> BitcoinTransactionPriority.all;
-
-	@override
-	List<TransactionPriority> getLitecoinTransactionPriorities()
-		=> LitecoinTransactionPriority.all;
-
-	@override
-	TransactionPriority deserializeBitcoinTransactionPriority(int raw)
-		=> BitcoinTransactionPriority.deserialize(raw: raw);
-
-	@override
-	TransactionPriority deserializeLitecoinTransactionPriority(int raw)
-		=> LitecoinTransactionPriority.deserialize(raw: raw);
-
-	@override
-	int getFeeRate(Object wallet, TransactionPriority priority) {
-		final bitcoinWallet = wallet as ElectrumWallet;
-		return bitcoinWallet.feeRate(priority);
-	}
-
-	@override
-	Future<void> generateNewAddress(Object wallet, String label) async {
-		final bitcoinWallet = wallet as ElectrumWallet;
-		await bitcoinWallet.walletAddresses.generateNewAddress(label: label, hd: bitcoinWallet.hd);
-		await wallet.save();
-	}
-
-	@override
-	Future<void> updateAddress(Object wallet,String address, String label) async {
-		final bitcoinWallet = wallet as ElectrumWallet;
-		bitcoinWallet.walletAddresses.updateAddress(address, label);
-		await wallet.save();
-	}
-	
-	@override
-	Object createBitcoinTransactionCredentials(List<Output> outputs, {required TransactionPriority priority, int? feeRate})
-		=> BitcoinTransactionCredentials(
-			outputs.map((out) => OutputInfo(
-					fiatAmount: out.fiatAmount,
-					cryptoAmount: out.cryptoAmount,
-					address: out.address,
-					note: out.note,
-					sendAll: out.sendAll,
-					extractedAddress: out.extractedAddress,
-					isParsedAddress: out.isParsedAddress,
-					formattedCryptoAmount: out.formattedCryptoAmount))
-			.toList(),
-			priority: priority as BitcoinTransactionPriority,
-			feeRate: feeRate);
-
-	@override
-	Object createBitcoinTransactionCredentialsRaw(List<OutputInfo> outputs, {TransactionPriority? priority, required int feeRate})
-		=> BitcoinTransactionCredentials(
-				outputs,
-				priority: priority != null ? priority as BitcoinTransactionPriority : null,
-				feeRate: feeRate);
-
-	@override
-	List<String> getAddresses(Object wallet) {
-		final bitcoinWallet = wallet as ElectrumWallet;
-		return bitcoinWallet.walletAddresses.addresses
-			.map((BitcoinAddressRecord addr) => addr.address)
-			.toList();
-	}
-
-	@override
-	@computed
-	List<ElectrumSubAddress> getSubAddresses(Object wallet) {
-		final electrumWallet = wallet as ElectrumWallet;
-		return electrumWallet.walletAddresses.addresses
-			.map((BitcoinAddressRecord addr) => ElectrumSubAddress(
-				id: addr.index,
-				name: addr.name,
-				address: electrumWallet.type == WalletType.bitcoinCash ? addr.cashAddr : addr.address,
-				txCount: addr.txCount,
-				balance: addr.balance,
-				isChange: addr.isHidden))
-			.toList();
-	}
-
-	@override
-	String getAddress(Object wallet) {
-		final bitcoinWallet = wallet as ElectrumWallet;
-		return bitcoinWallet.walletAddresses.address;
-	}
-
-	@override
-	String formatterBitcoinAmountToString({required int amount})
-		=> bitcoinAmountToString(amount: amount);
-
-	@override	
-	double formatterBitcoinAmountToDouble({required int amount})
-		=> bitcoinAmountToDouble(amount: amount);
-
-	@override	
-	int formatterStringDoubleToBitcoinAmount(String amount)
-		=> stringDoubleToBitcoinAmount(amount);
+  @override
+  TransactionPriority getMediumTransactionPriority() => BitcoinTransactionPriority.medium;
 
   @override
-  String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate)
-    => (priority as BitcoinTransactionPriority).labelWithRate(rate);
-
-	@override
-	List<BitcoinUnspent> getUnspents(Object wallet) {
-		final bitcoinWallet = wallet as ElectrumWallet;
-		return bitcoinWallet.unspentCoins;
-	}
-
-	Future<void> updateUnspents(Object wallet) async {
-		final bitcoinWallet = wallet as ElectrumWallet;
-		await bitcoinWallet.updateUnspent();
-	}
-
-	WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
-		return BitcoinWalletService(walletInfoSource, unspentCoinSource);
-	}
-
-	WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
-		return LitecoinWalletService(walletInfoSource, unspentCoinSource);
-	}
-  
-  @override
-  TransactionPriority getBitcoinTransactionPriorityMedium()
-    => BitcoinTransactionPriority.medium;
+  WalletCredentials createBitcoinRestoreWalletFromSeedCredentials(
+          {required String name, required String mnemonic, required String password}) =>
+      BitcoinRestoreWalletFromSeedCredentials(name: name, mnemonic: mnemonic, password: password);
 
   @override
-  TransactionPriority getLitecoinTransactionPriorityMedium()
-    => LitecoinTransactionPriority.medium;
+  WalletCredentials createBitcoinRestoreWalletFromWIFCredentials(
+          {required String name,
+          required String password,
+          required String wif,
+          WalletInfo? walletInfo}) =>
+      BitcoinRestoreWalletFromWIFCredentials(
+          name: name, password: password, wif: wif, walletInfo: walletInfo);
 
   @override
-  TransactionPriority getBitcoinTransactionPrioritySlow()
-    => BitcoinTransactionPriority.slow;
-  
+  WalletCredentials createBitcoinNewWalletCredentials(
+          {required String name, WalletInfo? walletInfo}) =>
+      BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo);
+
   @override
-  TransactionPriority getLitecoinTransactionPrioritySlow()
-    => LitecoinTransactionPriority.slow;
-}
\ No newline at end of file
+  List<String> getWordList() => wordlist;
+
+  @override
+  Map<String, String> getWalletKeys(Object wallet) {
+    final bitcoinWallet = wallet as ElectrumWallet;
+    final keys = bitcoinWallet.keys;
+
+    return <String, String>{
+      'wif': keys.wif,
+      'privateKey': keys.privateKey,
+      'publicKey': keys.publicKey
+    };
+  }
+
+  @override
+  List<TransactionPriority> getTransactionPriorities() => BitcoinTransactionPriority.all;
+
+  @override
+  List<TransactionPriority> getLitecoinTransactionPriorities() => LitecoinTransactionPriority.all;
+
+  @override
+  TransactionPriority deserializeBitcoinTransactionPriority(int raw) =>
+      BitcoinTransactionPriority.deserialize(raw: raw);
+
+  @override
+  TransactionPriority deserializeLitecoinTransactionPriority(int raw) =>
+      LitecoinTransactionPriority.deserialize(raw: raw);
+
+  @override
+  int getFeeRate(Object wallet, TransactionPriority priority) {
+    final bitcoinWallet = wallet as ElectrumWallet;
+    return bitcoinWallet.feeRate(priority);
+  }
+
+  @override
+  Future<void> generateNewAddress(Object wallet, String label) async {
+    final bitcoinWallet = wallet as ElectrumWallet;
+    await bitcoinWallet.walletAddresses.generateNewAddress(label: label);
+    await wallet.save();
+  }
+
+  @override
+  Future<void> updateAddress(Object wallet, String address, String label) async {
+    final bitcoinWallet = wallet as ElectrumWallet;
+    bitcoinWallet.walletAddresses.updateAddress(address, label);
+    await wallet.save();
+  }
+
+  @override
+  Object createBitcoinTransactionCredentials(List<Output> outputs,
+          {required TransactionPriority priority, int? feeRate}) =>
+      BitcoinTransactionCredentials(
+          outputs
+              .map((out) => OutputInfo(
+                  fiatAmount: out.fiatAmount,
+                  cryptoAmount: out.cryptoAmount,
+                  address: out.address,
+                  note: out.note,
+                  sendAll: out.sendAll,
+                  extractedAddress: out.extractedAddress,
+                  isParsedAddress: out.isParsedAddress,
+                  formattedCryptoAmount: out.formattedCryptoAmount))
+              .toList(),
+          priority: priority as BitcoinTransactionPriority,
+          feeRate: feeRate);
+
+  @override
+  Object createBitcoinTransactionCredentialsRaw(List<OutputInfo> outputs,
+          {TransactionPriority? priority, required int feeRate}) =>
+      BitcoinTransactionCredentials(outputs,
+          priority: priority != null ? priority as BitcoinTransactionPriority : null,
+          feeRate: feeRate);
+
+  @override
+  List<String> getAddresses(Object wallet) {
+    final bitcoinWallet = wallet as ElectrumWallet;
+    return bitcoinWallet.walletAddresses.addressesByReceiveType
+        .map((BitcoinAddressRecord addr) => addr.address)
+        .toList();
+  }
+
+  @override
+  @computed
+  List<ElectrumSubAddress> getSubAddresses(Object wallet) {
+    final electrumWallet = wallet as ElectrumWallet;
+    return electrumWallet.walletAddresses.addressesByReceiveType
+        .map((BitcoinAddressRecord addr) => ElectrumSubAddress(
+            id: addr.index,
+            name: addr.name,
+            address: electrumWallet.type == WalletType.bitcoinCash ? addr.cashAddr : addr.address,
+            txCount: addr.txCount,
+            balance: addr.balance,
+            isChange: addr.isHidden))
+        .toList();
+  }
+
+  @override
+  String getAddress(Object wallet) {
+    final bitcoinWallet = wallet as ElectrumWallet;
+    return bitcoinWallet.walletAddresses.address;
+  }
+
+  @override
+  String formatterBitcoinAmountToString({required int amount}) =>
+      bitcoinAmountToString(amount: amount);
+
+  @override
+  double formatterBitcoinAmountToDouble({required int amount}) =>
+      bitcoinAmountToDouble(amount: amount);
+
+  @override
+  int formatterStringDoubleToBitcoinAmount(String amount) => stringDoubleToBitcoinAmount(amount);
+
+  @override
+  String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate) =>
+      (priority as BitcoinTransactionPriority).labelWithRate(rate);
+
+  @override
+  List<BitcoinUnspent> getUnspents(Object wallet) {
+    final bitcoinWallet = wallet as ElectrumWallet;
+    return bitcoinWallet.unspentCoins;
+  }
+
+  Future<void> updateUnspents(Object wallet) async {
+    final bitcoinWallet = wallet as ElectrumWallet;
+    await bitcoinWallet.updateUnspent();
+  }
+
+  WalletService createBitcoinWalletService(
+      Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
+    return BitcoinWalletService(walletInfoSource, unspentCoinSource);
+  }
+
+  WalletService createLitecoinWalletService(
+      Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
+    return LitecoinWalletService(walletInfoSource, unspentCoinSource);
+  }
+
+  @override
+  TransactionPriority getBitcoinTransactionPriorityMedium() => BitcoinTransactionPriority.medium;
+
+  @override
+  TransactionPriority getLitecoinTransactionPriorityMedium() => LitecoinTransactionPriority.medium;
+
+  @override
+  TransactionPriority getBitcoinTransactionPrioritySlow() => BitcoinTransactionPriority.slow;
+
+  @override
+  TransactionPriority getLitecoinTransactionPrioritySlow() => LitecoinTransactionPriority.slow;
+
+  @override
+  Future<void> setAddressType(Object wallet, dynamic option) async {
+    final bitcoinWallet = wallet as ElectrumWallet;
+    await bitcoinWallet.walletAddresses.setAddressType(option as BitcoinAddressType);
+  }
+
+  @override
+  BitcoinReceivePageOption getSelectedAddressType(Object wallet) {
+    final bitcoinWallet = wallet as ElectrumWallet;
+    return BitcoinReceivePageOption.fromType(bitcoinWallet.walletAddresses.addressPageType);
+  }
+
+  @override
+  List<BitcoinReceivePageOption> getBitcoinReceivePageOptions() => BitcoinReceivePageOption.all;
+}
diff --git a/lib/core/address_validator.dart b/lib/core/address_validator.dart
index 21f3c3557..432471655 100644
--- a/lib/core/address_validator.dart
+++ b/lib/core/address_validator.dart
@@ -1,4 +1,4 @@
-import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:cake_wallet/generated/i18n.dart';
 import 'package:cake_wallet/core/validator.dart';
 import 'package:cake_wallet/solana/solana.dart';
@@ -9,7 +9,9 @@ class AddressValidator extends TextValidator {
   AddressValidator({required CryptoCurrency type})
       : super(
             errorMessage: S.current.error_text_address,
-            useAdditionalValidation: type == CryptoCurrency.btc ? bitcoin.Address.validateAddress : null,
+            useAdditionalValidation: type == CryptoCurrency.btc
+                ? (String txt) => validateAddress(address: txt, network: BitcoinNetwork.mainnet)
+                : null,
             pattern: getPattern(type),
             length: getLength(type));
 
@@ -24,7 +26,7 @@ class AddressValidator extends TextValidator {
         return '^[0-9a-zA-Z]{59}\$|^[0-9a-zA-Z]{92}\$|^[0-9a-zA-Z]{104}\$'
             '|^[0-9a-zA-Z]{105}\$|^addr1[0-9a-zA-Z]{98}\$';
       case CryptoCurrency.btc:
-        return '^3[0-9a-zA-Z]{32}\$|^3[0-9a-zA-Z]{33}\$|^bc1[0-9a-zA-Z]{59}\$';
+        return '^${P2pkhAddress.regex.pattern}\$|^${P2shAddress.regex.pattern}\$|^${P2wpkhAddress.regex.pattern}\$|${P2trAddress.regex.pattern}\$|^${P2wshAddress.regex.pattern}\$';
       case CryptoCurrency.nano:
         return '[0-9a-zA-Z_]';
       case CryptoCurrency.banano:
@@ -89,7 +91,7 @@ class AddressValidator extends TextValidator {
       case CryptoCurrency.dai:
       case CryptoCurrency.dash:
       case CryptoCurrency.eos:
-      return '[0-9a-zA-Z]';
+        return '[0-9a-zA-Z]';
       case CryptoCurrency.bch:
         return '^(?!bitcoincash:)[0-9a-zA-Z]*\$|^(?!bitcoincash:)q|p[0-9a-zA-Z]{41}\$|^(?!bitcoincash:)q|p[0-9a-zA-Z]{42}\$|^bitcoincash:q|p[0-9a-zA-Z]{41}\$|^bitcoincash:q|p[0-9a-zA-Z]{42}\$';
       case CryptoCurrency.bnb:
@@ -268,12 +270,11 @@ class AddressValidator extends TextValidator {
             '|([^0-9a-zA-Z]|^)8[0-9a-zA-Z]{94}([^0-9a-zA-Z]|\$)'
             '|([^0-9a-zA-Z]|^)[0-9a-zA-Z]{106}([^0-9a-zA-Z]|\$)';
       case CryptoCurrency.btc:
-        return '([^0-9a-zA-Z]|^)1[0-9a-zA-Z]{32}([^0-9a-zA-Z]|\$)'
-            '|([^0-9a-zA-Z]|^)1[0-9a-zA-Z]{33}([^0-9a-zA-Z]|\$)'
-            '|([^0-9a-zA-Z]|^)3[0-9a-zA-Z]{32}([^0-9a-zA-Z]|\$)'
-            '|([^0-9a-zA-Z]|^)3[0-9a-zA-Z]{33}([^0-9a-zA-Z]|\$)'
-            '|([^0-9a-zA-Z]|^)bc1[0-9a-zA-Z]{39}([^0-9a-zA-Z]|\$)'
-            '|([^0-9a-zA-Z]|^)bc1[0-9a-zA-Z]{59}([^0-9a-zA-Z]|\$)';
+        return '([^0-9a-zA-Z]|^)${P2pkhAddress.regex.pattern}|\$)'
+            '([^0-9a-zA-Z]|^)${P2shAddress.regex.pattern}|\$)'
+            '([^0-9a-zA-Z]|^)${P2wpkhAddress.regex.pattern}|\$)'
+            '([^0-9a-zA-Z]|^)${P2wshAddress.regex.pattern}|\$)'
+            '([^0-9a-zA-Z]|^)${P2trAddress.regex.pattern}|\$)';
       case CryptoCurrency.ltc:
         return '([^0-9a-zA-Z]|^)^L[a-zA-Z0-9]{26,33}([^0-9a-zA-Z]|\$)'
             '|([^0-9a-zA-Z]|^)[LM][a-km-zA-HJ-NP-Z1-9]{26,33}([^0-9a-zA-Z]|\$)'
@@ -297,4 +298,4 @@ class AddressValidator extends TextValidator {
         return null;
     }
   }
-}
\ No newline at end of file
+}
diff --git a/lib/core/wallet_creation_service.dart b/lib/core/wallet_creation_service.dart
index 8548f079f..31a893ad6 100644
--- a/lib/core/wallet_creation_service.dart
+++ b/lib/core/wallet_creation_service.dart
@@ -2,7 +2,6 @@ import 'package:cake_wallet/di.dart';
 import 'package:cake_wallet/store/settings_store.dart';
 import 'package:cw_core/wallet_info.dart';
 import 'package:cake_wallet/entities/preferences_key.dart';
-import 'package:flutter/foundation.dart';
 import 'package:flutter_secure_storage/flutter_secure_storage.dart';
 import 'package:hive/hive.dart';
 import 'package:shared_preferences/shared_preferences.dart';
@@ -55,7 +54,7 @@ class WalletCreationService {
     }
   }
 
-  Future<WalletBase> create(WalletCredentials credentials) async {
+  Future<WalletBase> create(WalletCredentials credentials, {bool? isTestnet}) async {
     checkIfExists(credentials.name);
     final password = generateWalletPassword();
     credentials.password = password;
@@ -63,7 +62,7 @@ class WalletCreationService {
       credentials.seedPhraseLength = settingsStore.seedPhraseLength.value;
     }
     await keyService.saveWalletPassword(password: password, walletName: credentials.name);
-    final wallet = await _service!.create(credentials);
+    final wallet = await _service!.create(credentials, isTestnet: isTestnet);
 
     if (wallet.type == WalletType.monero) {
       await sharedPreferences.setBool(
@@ -73,12 +72,12 @@ class WalletCreationService {
     return wallet;
   }
 
-  Future<WalletBase> restoreFromKeys(WalletCredentials credentials) async {
+  Future<WalletBase> restoreFromKeys(WalletCredentials credentials, {bool? isTestnet}) async {
     checkIfExists(credentials.name);
     final password = generateWalletPassword();
     credentials.password = password;
     await keyService.saveWalletPassword(password: password, walletName: credentials.name);
-    final wallet = await _service!.restoreFromKeys(credentials);
+    final wallet = await _service!.restoreFromKeys(credentials, isTestnet: isTestnet);
 
     if (wallet.type == WalletType.monero) {
       await sharedPreferences.setBool(
@@ -88,12 +87,12 @@ class WalletCreationService {
     return wallet;
   }
 
-  Future<WalletBase> restoreFromSeed(WalletCredentials credentials) async {
+  Future<WalletBase> restoreFromSeed(WalletCredentials credentials, {bool? isTestnet}) async {
     checkIfExists(credentials.name);
     final password = generateWalletPassword();
     credentials.password = password;
     await keyService.saveWalletPassword(password: password, walletName: credentials.name);
-    final wallet = await _service!.restoreFromSeed(credentials);
+    final wallet = await _service!.restoreFromSeed(credentials, isTestnet: isTestnet);
 
     if (wallet.type == WalletType.monero) {
       await sharedPreferences.setBool(
diff --git a/lib/di.dart b/lib/di.dart
index 74a425579..a735d8c05 100644
--- a/lib/di.dart
+++ b/lib/di.dart
@@ -14,7 +14,7 @@ import 'package:cake_wallet/core/yat_service.dart';
 import 'package:cake_wallet/entities/background_tasks.dart';
 import 'package:cake_wallet/entities/exchange_api_mode.dart';
 import 'package:cake_wallet/entities/parse_address_from_domain.dart';
-import 'package:cake_wallet/entities/receive_page_option.dart';
+import 'package:cw_core/receive_page_option.dart';
 import 'package:cake_wallet/ethereum/ethereum.dart';
 import 'package:cake_wallet/lightning/lightning.dart';
 import 'package:cake_wallet/nano/nano.dart';
diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart
index 019276227..fb3e9e80c 100644
--- a/lib/entities/default_settings_migration.dart
+++ b/lib/entities/default_settings_migration.dart
@@ -23,6 +23,10 @@ import 'package:collection/collection.dart';
 
 const newCakeWalletMoneroUri = 'xmr-node.cakewallet.com:18081';
 const cakeWalletBitcoinElectrumUri = 'electrum.cakewallet.com:50002';
+const publicBitcoinTestnetElectrumAddress = 'electrum.blockstream.info';
+const publicBitcoinTestnetElectrumPort = '60002';
+const publicBitcoinTestnetElectrumUri =
+    '$publicBitcoinTestnetElectrumAddress:$publicBitcoinTestnetElectrumPort';
 const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002';
 const havenDefaultNodeUri = 'nodes.havenprotocol.org:443';
 const ethereumDefaultNodeUri = 'ethereum.publicnode.com';
@@ -334,6 +338,12 @@ Node? getBitcoinDefaultElectrumServer({required Box<Node> nodes}) {
       nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoin);
 }
 
+Node? getBitcoinTestnetDefaultElectrumServer({required Box<Node> nodes}) {
+  return nodes.values
+          .firstWhereOrNull((Node node) => node.uriRaw == publicBitcoinTestnetElectrumUri) ??
+      nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoin);
+}
+
 Node? getLitecoinDefaultElectrumServer({required Box<Node> nodes}) {
   return nodes.values
           .firstWhereOrNull((Node node) => node.uriRaw == cakeWalletLitecoinElectrumUri) ??
@@ -503,8 +513,15 @@ Future<void> rewriteSecureStoragePin({required FlutterSecureStorage secureStorag
 }
 
 Future<void> changeBitcoinCurrentElectrumServerToDefault(
-    {required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
-  final server = getBitcoinDefaultElectrumServer(nodes: nodes);
+    {required SharedPreferences sharedPreferences,
+    required Box<Node> nodes,
+    bool? isTestnet}) async {
+  Node? server;
+  if (isTestnet == true) {
+    server = getBitcoinTestnetDefaultElectrumServer(nodes: nodes);
+  } else {
+    server = getBitcoinDefaultElectrumServer(nodes: nodes);
+  }
   final serverId = server?.key as int? ?? 0;
 
   await sharedPreferences.setInt(PreferencesKey.currentBitcoinElectrumSererIdKey, serverId);
diff --git a/lib/router.dart b/lib/router.dart
index a09aee554..a198663cd 100644
--- a/lib/router.dart
+++ b/lib/router.dart
@@ -535,13 +535,19 @@ Route<dynamic> createRoute(RouteSettings settings) {
           builder: (_) => getIt.get<WebViewPage>(param1: title, param2: url));
 
     case Routes.advancedPrivacySettings:
-      final type = settings.arguments as WalletType;
+      final args = settings.arguments as Map<String, dynamic>;
+      final type = args['type'] as WalletType;
+      final useTestnet = args['useTestnet'] as bool;
+      final toggleTestnet = args['toggleTestnet'] as Function(bool? val);
 
       return CupertinoPageRoute<void>(
           builder: (_) => AdvancedPrivacySettingsPage(
-              getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
-              getIt.get<NodeCreateOrEditViewModel>(param1: type, param2: false),
-              getIt.get<SeedTypeViewModel>()));
+                useTestnet,
+                toggleTestnet,
+                getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
+                getIt.get<NodeCreateOrEditViewModel>(param1: type, param2: false),
+                getIt.get<SeedTypeViewModel>(),
+              ));
 
     case Routes.anonPayInvoicePage:
       final args = settings.arguments as List;
diff --git a/lib/src/screens/dashboard/pages/address_page.dart b/lib/src/screens/dashboard/pages/address_page.dart
index 4c4d50ce5..120b88b1d 100644
--- a/lib/src/screens/dashboard/pages/address_page.dart
+++ b/lib/src/screens/dashboard/pages/address_page.dart
@@ -7,7 +7,8 @@ import 'package:cake_wallet/src/screens/base_page.dart';
 import 'package:cake_wallet/src/screens/monero_accounts/monero_account_list_page.dart';
 import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart';
 import 'package:cake_wallet/entities/preferences_key.dart';
-import 'package:cake_wallet/entities/receive_page_option.dart';
+import 'package:cw_core/receive_page_option.dart';
+import 'package:cw_bitcoin/bitcoin_receive_page_option.dart';
 import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
 import 'package:cake_wallet/src/widgets/gradient_background.dart';
 import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
@@ -29,6 +30,7 @@ import 'package:keyboard_actions/keyboard_actions.dart';
 import 'package:mobx/mobx.dart';
 import 'package:shared_preferences/shared_preferences.dart';
 import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
+import 'package:bitcoin_base/bitcoin_base.dart';
 
 class AddressPage extends BasePage {
   AddressPage({
@@ -232,6 +234,21 @@ class AddressPage extends BasePage {
             );
           }
           break;
+        case BitcoinReceivePageOption.p2pkh:
+          addressListViewModel.setAddressType(P2pkhAddressType.p2pkh);
+          break;
+        case BitcoinReceivePageOption.p2sh:
+          addressListViewModel.setAddressType(P2shAddressType.p2wpkhInP2sh);
+          break;
+        case BitcoinReceivePageOption.p2wpkh:
+          addressListViewModel.setAddressType(SegwitAddresType.p2wpkh);
+          break;
+        case BitcoinReceivePageOption.p2tr:
+          addressListViewModel.setAddressType(SegwitAddresType.p2tr);
+          break;
+        case BitcoinReceivePageOption.p2wsh:
+          addressListViewModel.setAddressType(SegwitAddresType.p2wsh);
+          break;
         default:
       }
     });
diff --git a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart
index a4bd6c7b9..26478345e 100644
--- a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart
+++ b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart
@@ -1,3 +1,4 @@
+import 'package:cake_wallet/entities/default_settings_migration.dart';
 import 'package:cake_wallet/entities/exchange_api_mode.dart';
 import 'package:cake_wallet/entities/fiat_api_mode.dart';
 import 'package:cake_wallet/entities/seed_phrase_length.dart';
@@ -11,6 +12,7 @@ import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.
 import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
 import 'package:cake_wallet/view_model/seed_type_view_model.dart';
 import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
+import 'package:cw_core/wallet_type.dart';
 import 'package:flutter_mobx/flutter_mobx.dart';
 import 'package:flutter/material.dart';
 import 'package:cake_wallet/generated/i18n.dart';
@@ -19,7 +21,7 @@ import 'package:cake_wallet/src/widgets/primary_button.dart';
 import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
 
 class AdvancedPrivacySettingsPage extends BasePage {
-  AdvancedPrivacySettingsPage(
+  AdvancedPrivacySettingsPage(this.useTestnet, this.toggleUseTestnet,
       this.advancedPrivacySettingsViewModel, this.nodeViewModel, this.seedTypeViewModel);
 
   final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel;
@@ -29,13 +31,16 @@ class AdvancedPrivacySettingsPage extends BasePage {
   @override
   String get title => S.current.privacy_settings;
 
+  final bool useTestnet;
+  final Function(bool? val) toggleUseTestnet;
+
   @override
-  Widget body(BuildContext context) => AdvancedPrivacySettingsBody(
+  Widget body(BuildContext context) => AdvancedPrivacySettingsBody(useTestnet, toggleUseTestnet,
       advancedPrivacySettingsViewModel, nodeViewModel, seedTypeViewModel);
 }
 
 class AdvancedPrivacySettingsBody extends StatefulWidget {
-  const AdvancedPrivacySettingsBody(
+  const AdvancedPrivacySettingsBody(this.useTestnet, this.toggleUseTestnet,
       this.privacySettingsViewModel, this.nodeViewModel, this.seedTypeViewModel,
       {Key? key})
       : super(key: key);
@@ -44,6 +49,9 @@ class AdvancedPrivacySettingsBody extends StatefulWidget {
   final NodeCreateOrEditViewModel nodeViewModel;
   final SeedTypeViewModel seedTypeViewModel;
 
+  final bool useTestnet;
+  final Function(bool? val) toggleUseTestnet;
+
   @override
   _AdvancedPrivacySettingsBodyState createState() => _AdvancedPrivacySettingsBodyState();
 }
@@ -52,9 +60,14 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
   _AdvancedPrivacySettingsBodyState();
 
   final _formKey = GlobalKey<FormState>();
+  bool? testnetValue;
 
   @override
   Widget build(BuildContext context) {
+    if (testnetValue == null && widget.useTestnet != null) {
+      testnetValue = widget.useTestnet;
+    }
+
     return Container(
       padding: EdgeInsets.only(top: 24),
       child: ScrollableWithBottomSection(
@@ -125,6 +138,19 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
                   ),
                 );
               }),
+            if (widget.privacySettingsViewModel.type == WalletType.bitcoin)
+              Builder(builder: (_) {
+                final val = testnetValue!;
+                return SettingsSwitcherCell(
+                    title: S.current.use_testnet,
+                    value: val,
+                    onValueChange: (_, __) {
+                      setState(() {
+                        testnetValue = !val;
+                      });
+                      widget.toggleUseTestnet!.call(testnetValue);
+                    });
+              }),
           ],
         ),
         bottomSectionPadding: EdgeInsets.all(24),
@@ -137,6 +163,13 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
                     return;
                   }
 
+                  widget.nodeViewModel.save();
+                } else if (testnetValue == true) {
+                  // TODO: add type (mainnet/testnet) to Node class so when switching wallets the node can be switched to a matching type
+                  // Currently this is so you can create a working testnet wallet but you need to keep switching back the node if you use multiple wallets at once
+                  widget.nodeViewModel.address = publicBitcoinTestnetElectrumAddress;
+                  widget.nodeViewModel.port = publicBitcoinTestnetElectrumPort;
+
                   widget.nodeViewModel.save();
                 }
 
diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart
index 499e5feff..8cc8a138d 100644
--- a/lib/src/screens/new_wallet/new_wallet_page.dart
+++ b/lib/src/screens/new_wallet/new_wallet_page.dart
@@ -40,7 +40,9 @@ class NewWalletPage extends BasePage {
 
   @override
   Widget body(BuildContext context) => WalletNameForm(
-      _walletNewVM, currentTheme.type == ThemeType.dark ? walletNameImage : walletNameLightImage, _seedTypeViewModel);
+      _walletNewVM,
+      currentTheme.type == ThemeType.dark ? walletNameImage : walletNameLightImage,
+      _seedTypeViewModel);
 }
 
 class WalletNameForm extends StatefulWidget {
@@ -187,7 +189,6 @@ class _WalletNameFormState extends State<WalletNameForm> {
                       ),
                     ),
                   ),
-
                   if (_walletNewVM.hasLanguageSelector) ...[
                     if (_walletNewVM.hasSeedType) ...[
                       Observer(
@@ -222,7 +223,7 @@ class _WalletNameFormState extends State<WalletNameForm> {
                         ),
                       ),
                     )
-                  ]
+                  ],
                 ],
               ),
             ),
@@ -245,8 +246,11 @@ class _WalletNameFormState extends State<WalletNameForm> {
               const SizedBox(height: 25),
               GestureDetector(
                 onTap: () {
-                  Navigator.of(context)
-                      .pushNamed(Routes.advancedPrivacySettings, arguments: _walletNewVM.type);
+                  Navigator.of(context).pushNamed(Routes.advancedPrivacySettings, arguments: {
+                    "type": _walletNewVM.type,
+                    "useTestnet": _walletNewVM.useTestnet,
+                    "toggleTestnet": _walletNewVM.toggleUseTestnet
+                  });
                 },
                 child: Text(S.of(context).advanced_settings),
               ),
diff --git a/lib/src/screens/receive/anonpay_invoice_page.dart b/lib/src/screens/receive/anonpay_invoice_page.dart
index fc835c72d..f33cdcc5b 100644
--- a/lib/src/screens/receive/anonpay_invoice_page.dart
+++ b/lib/src/screens/receive/anonpay_invoice_page.dart
@@ -4,7 +4,7 @@ import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart';
 import 'package:cake_wallet/core/execution_state.dart';
 import 'package:cake_wallet/di.dart';
 import 'package:cake_wallet/entities/preferences_key.dart';
-import 'package:cake_wallet/entities/receive_page_option.dart';
+import 'package:cw_core/receive_page_option.dart';
 import 'package:cake_wallet/routes.dart';
 import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
 import 'package:cake_wallet/src/screens/receive/widgets/anonpay_input_form.dart';
diff --git a/lib/src/screens/receive/anonpay_receive_page.dart b/lib/src/screens/receive/anonpay_receive_page.dart
index b602abde6..7d71e3a22 100644
--- a/lib/src/screens/receive/anonpay_receive_page.dart
+++ b/lib/src/screens/receive/anonpay_receive_page.dart
@@ -1,7 +1,7 @@
 import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
 import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
 import 'package:cake_wallet/entities/qr_view_data.dart';
-import 'package:cake_wallet/entities/receive_page_option.dart';
+import 'package:cw_core/receive_page_option.dart';
 import 'package:cake_wallet/generated/i18n.dart';
 import 'package:cake_wallet/routes.dart';
 import 'package:cake_wallet/src/screens/base_page.dart';
diff --git a/lib/src/screens/restore/wallet_restore_page.dart b/lib/src/screens/restore/wallet_restore_page.dart
index 899aacd19..fe5ac8487 100644
--- a/lib/src/screens/restore/wallet_restore_page.dart
+++ b/lib/src/screens/restore/wallet_restore_page.dart
@@ -210,8 +210,12 @@ class WalletRestorePage extends BasePage {
                       const SizedBox(height: 25),
                       GestureDetector(
                         onTap: () {
-                          Navigator.of(context).pushNamed(Routes.advancedPrivacySettings,
-                              arguments: walletRestoreViewModel.type);
+                          Navigator.of(context)
+                              .pushNamed(Routes.advancedPrivacySettings, arguments: {
+                            'type': walletRestoreViewModel.type,
+                            'useTestnet': walletRestoreViewModel.useTestnet,
+                            'toggleTestnet': walletRestoreViewModel.toggleUseTestnet
+                          });
                         },
                         child: Text(S.of(context).advanced_settings),
                       ),
diff --git a/lib/view_model/anon_invoice_page_view_model.dart b/lib/view_model/anon_invoice_page_view_model.dart
index 53e8473a0..187eea375 100644
--- a/lib/view_model/anon_invoice_page_view_model.dart
+++ b/lib/view_model/anon_invoice_page_view_model.dart
@@ -4,7 +4,7 @@ import 'package:cake_wallet/anonpay/anonpay_request.dart';
 import 'package:cake_wallet/core/execution_state.dart';
 import 'package:cake_wallet/entities/fiat_currency.dart';
 import 'package:cake_wallet/entities/preferences_key.dart';
-import 'package:cake_wallet/entities/receive_page_option.dart';
+import 'package:cw_core/receive_page_option.dart';
 import 'package:cake_wallet/store/settings_store.dart';
 import 'package:cw_core/crypto_currency.dart';
 import 'package:cw_core/currency.dart';
diff --git a/lib/view_model/dashboard/dashboard_view_model.dart b/lib/view_model/dashboard/dashboard_view_model.dart
index a794c2262..da5eb0373 100644
--- a/lib/view_model/dashboard/dashboard_view_model.dart
+++ b/lib/view_model/dashboard/dashboard_view_model.dart
@@ -148,17 +148,21 @@ abstract class DashboardViewModelBase with Store {
               monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id)
           .toList();
 
-      transactions = ObservableList.of(_accountTransactions.map((transaction) =>
-          TransactionListItem(
-              transaction: transaction,
-              balanceViewModel: balanceViewModel,
-              settingsStore: appStore.settingsStore)));
+      final sortedTransactions = [..._accountTransactions];
+      sortedTransactions.sort((a, b) => a.date.compareTo(b.date));
+
+      transactions = ObservableList.of(sortedTransactions.map((transaction) => TransactionListItem(
+          transaction: transaction,
+          balanceViewModel: balanceViewModel,
+          settingsStore: appStore.settingsStore)));
     } else {
-      transactions = ObservableList.of(wallet.transactionHistory.transactions.values.map(
-          (transaction) => TransactionListItem(
-              transaction: transaction,
-              balanceViewModel: balanceViewModel,
-              settingsStore: appStore.settingsStore)));
+      final sortedTransactions = [...wallet.transactionHistory.transactions.values];
+      sortedTransactions.sort((a, b) => a.date.compareTo(b.date));
+
+      transactions = ObservableList.of(sortedTransactions.map((transaction) => TransactionListItem(
+          transaction: transaction,
+          balanceViewModel: balanceViewModel,
+          settingsStore: appStore.settingsStore)));
     }
 
     // TODO: nano sub-account generation is disabled:
diff --git a/lib/view_model/dashboard/receive_option_view_model.dart b/lib/view_model/dashboard/receive_option_view_model.dart
index 9bc4c0ba9..09c5ba078 100644
--- a/lib/view_model/dashboard/receive_option_view_model.dart
+++ b/lib/view_model/dashboard/receive_option_view_model.dart
@@ -1,4 +1,5 @@
-import 'package:cake_wallet/entities/receive_page_option.dart';
+import 'package:cake_wallet/bitcoin/bitcoin.dart';
+import 'package:cw_core/receive_page_option.dart';
 import 'package:cw_core/wallet_base.dart';
 import 'package:cw_core/wallet_type.dart';
 import 'package:mobx/mobx.dart';
@@ -9,7 +10,10 @@ class ReceiveOptionViewModel = ReceiveOptionViewModelBase with _$ReceiveOptionVi
 
 abstract class ReceiveOptionViewModelBase with Store {
   ReceiveOptionViewModelBase(this._wallet, this.initialPageOption)
-      : selectedReceiveOption = initialPageOption ?? ReceivePageOption.mainnet,
+      : selectedReceiveOption = initialPageOption ??
+            (_wallet.type == WalletType.bitcoin
+                ? bitcoin!.getSelectedAddressType(_wallet)
+                : ReceivePageOption.mainnet),
         _options = [] {
     final walletType = _wallet.type;
 
@@ -20,8 +24,18 @@ abstract class ReceiveOptionViewModelBase with Store {
       case WalletType.lightning:
         _options = [ReceivePageOption.lightningInvoice, ReceivePageOption.lightningOnchain];
         break;
+      case WalletType.bitcoin:
+        _options = [
+          ...bitcoin!.getBitcoinReceivePageOptions(),
+          ...ReceivePageOptions.where((element) => element != ReceivePageOption.mainnet)
+        ];
+        break;
       default:
-        _options = [ReceivePageOption.mainnet, ReceivePageOption.anonPayDonationLink, ReceivePageOption.anonPayInvoice];
+        _options = [
+          ReceivePageOption.mainnet,
+          ReceivePageOption.anonPayDonationLink,
+          ReceivePageOption.anonPayInvoice
+        ];
         break;
     }
   }
diff --git a/lib/view_model/node_list/node_create_or_edit_view_model.dart b/lib/view_model/node_list/node_create_or_edit_view_model.dart
index 0fb9a83c6..e323268a0 100644
--- a/lib/view_model/node_list/node_create_or_edit_view_model.dart
+++ b/lib/view_model/node_list/node_create_or_edit_view_model.dart
@@ -65,6 +65,8 @@ abstract class NodeCreateOrEditViewModelBase with Store {
   bool get hasAuthCredentials =>
       _walletType == WalletType.monero || _walletType == WalletType.haven;
 
+  bool get hasTestnetSupport => _walletType == WalletType.bitcoin;
+
   String get uri {
     var uri = address;
 
diff --git a/lib/view_model/node_list/node_list_view_model.dart b/lib/view_model/node_list/node_list_view_model.dart
index b78c95f70..7bac4bc6c 100644
--- a/lib/view_model/node_list/node_list_view_model.dart
+++ b/lib/view_model/node_list/node_list_view_model.dart
@@ -52,7 +52,11 @@ abstract class NodeListViewModelBase with Store {
 
     switch (_appStore.wallet!.type) {
       case WalletType.bitcoin:
-        node = getBitcoinDefaultElectrumServer(nodes: _nodeSource)!;
+        if (_appStore.wallet!.isTestnet == true) {
+          node = getBitcoinTestnetDefaultElectrumServer(nodes: _nodeSource)!;
+        } else {
+          node = getBitcoinDefaultElectrumServer(nodes: _nodeSource)!;
+        }
         break;
       case WalletType.lightning:
         node = getBitcoinDefaultElectrumServer(nodes: _nodeSource)!;
diff --git a/lib/view_model/transaction_details_view_model.dart b/lib/view_model/transaction_details_view_model.dart
index 572e3b6a9..3deb1873e 100644
--- a/lib/view_model/transaction_details_view_model.dart
+++ b/lib/view_model/transaction_details_view_model.dart
@@ -119,7 +119,7 @@ abstract class TransactionDetailsViewModelBase with Store {
       case WalletType.monero:
         return 'https://monero.com/tx/${txId}';
       case WalletType.bitcoin:
-        return 'https://mempool.space/tx/${txId}';
+        return 'https://mempool.space/${wallet.isTestnet == true ? "testnet/" : ""}tx/${txId}';
       case WalletType.litecoin:
         return 'https://blockchair.com/litecoin/transaction/${txId}';
       case WalletType.bitcoinCash:
diff --git a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart
index c5618b6ae..4ccb3ee3b 100644
--- a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart
+++ b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart
@@ -402,9 +402,6 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
       wallet.type == WalletType.bitcoin ||
       wallet.type == WalletType.litecoin;
 
-  // wallet.type == WalletType.nano ||
-  // wallet.type == WalletType.banano; TODO: nano accounts are disabled for now
-
   @computed
   bool get isElectrumWallet =>
       wallet.type == WalletType.bitcoin ||
@@ -423,16 +420,17 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
   void setAddress(WalletAddressListItem address) =>
       wallet.walletAddresses.address = address.address;
 
+  @action
+  Future<void> setAddressType(dynamic option) async {
+    if (wallet.type == WalletType.bitcoin) {
+      await bitcoin!.setAddressType(wallet, option);
+    }
+  }
+
   void _init() {
     _baseItems = [];
 
-    if (wallet.type == WalletType.monero ||
-            wallet.type ==
-                WalletType
-                    .haven /*||
-        wallet.type == WalletType.nano ||
-        wallet.type == WalletType.banano*/
-        ) {
+    if (wallet.type == WalletType.monero || wallet.type == WalletType.haven) {
       _baseItems.add(WalletAccountListHeader());
     }
 
diff --git a/lib/view_model/wallet_creation_vm.dart b/lib/view_model/wallet_creation_vm.dart
index 45306905c..4a1e054d6 100644
--- a/lib/view_model/wallet_creation_vm.dart
+++ b/lib/view_model/wallet_creation_vm.dart
@@ -23,6 +23,12 @@ abstract class WalletCreationVMBase with Store {
       : state = InitialExecutionState(),
         name = '';
 
+  @observable
+  bool _useTestnet = false;
+
+  @computed
+  bool get useTestnet => _useTestnet;
+
   @observable
   String name;
 
@@ -94,4 +100,9 @@ abstract class WalletCreationVMBase with Store {
   Future<WalletBase> processFromRestoredWallet(
           WalletCredentials credentials, RestoredWallet restoreWallet) =>
       throw UnimplementedError();
+
+  @action
+  void toggleUseTestnet(bool? value) {
+    _useTestnet = value ?? !_useTestnet;
+  }
 }
diff --git a/lib/view_model/wallet_new_vm.dart b/lib/view_model/wallet_new_vm.dart
index f950838ce..cc4ac20fe 100644
--- a/lib/view_model/wallet_new_vm.dart
+++ b/lib/view_model/wallet_new_vm.dart
@@ -91,6 +91,6 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
   @override
   Future<WalletBase> process(WalletCredentials credentials) async {
     walletCreationService.changeWalletType(type: type);
-    return walletCreationService.create(credentials);
+    return walletCreationService.create(credentials, isTestnet: useTestnet);
   }
 }
diff --git a/lib/view_model/wallet_restore_view_model.dart b/lib/view_model/wallet_restore_view_model.dart
index 8ad9d830d..3b74374b5 100644
--- a/lib/view_model/wallet_restore_view_model.dart
+++ b/lib/view_model/wallet_restore_view_model.dart
@@ -213,9 +213,9 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
   @override
   Future<WalletBase> process(WalletCredentials credentials) async {
     if (mode == WalletRestoreMode.keys) {
-      return walletCreationService.restoreFromKeys(credentials);
+      return walletCreationService.restoreFromKeys(credentials, isTestnet: useTestnet);
     }
 
-    return walletCreationService.restoreFromSeed(credentials);
+    return walletCreationService.restoreFromSeed(credentials, isTestnet: useTestnet);
   }
 }
diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb
index c6ec298ca..99d9a3223 100644
--- a/res/values/strings_ar.arb
+++ b/res/values/strings_ar.arb
@@ -722,6 +722,7 @@
   "use_card_info_two": "يتم تحويل الأموال إلى الدولار الأمريكي عند الاحتفاظ بها في الحساب المدفوع مسبقًا ، وليس بالعملات الرقمية.",
   "use_ssl": "استخدم SSL",
   "use_suggested": "استخدام المقترح",
+  "use_testnet": "استخدم testnet",
   "variable_pair_not_supported": "هذا الزوج المتغير غير مدعوم في التبادلات المحددة",
   "verification": "تَحَقّق",
   "verify_with_2fa": "تحقق مع Cake 2FA",
diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb
index 54ecf5042..e7090fcf9 100644
--- a/res/values/strings_bg.arb
+++ b/res/values/strings_bg.arb
@@ -722,6 +722,7 @@
   "use_card_info_two": "Средствата се обръщат в USD, когато биват запазени в предплатената карта, а не в дигитална валута.",
   "use_ssl": "Използване на SSL",
   "use_suggested": "Използване на предложеното",
+  "use_testnet": "Използвайте TestNet",
   "variable_pair_not_supported": "Този variable pair не се поддържа от избраната борса",
   "verification": "Потвърждаване",
   "verify_with_2fa": "Проверете с Cake 2FA",
diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb
index 285533110..ba92ff0a4 100644
--- a/res/values/strings_cs.arb
+++ b/res/values/strings_cs.arb
@@ -722,6 +722,7 @@
   "use_card_info_two": "Prostředky jsou převedeny na USD, když jsou drženy na předplaceném účtu, nikoliv na digitální měnu.",
   "use_ssl": "Použít SSL",
   "use_suggested": "Použít doporučený",
+  "use_testnet": "Použijte testNet",
   "variable_pair_not_supported": "Tento pár s tržním kurzem není ve zvolené směnárně podporován",
   "verification": "Ověření",
   "verify_with_2fa": "Ověřte pomocí Cake 2FA",
diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb
index 002399aa0..dcd76ded4 100644
--- a/res/values/strings_de.arb
+++ b/res/values/strings_de.arb
@@ -724,6 +724,7 @@
   "use_card_info_two": "Guthaben werden auf dem Prepaid-Konto in USD umgerechnet, nicht in digitale Währung.",
   "use_ssl": "SSL verwenden",
   "use_suggested": "Vorgeschlagen verwenden",
+  "use_testnet": "TESTNET verwenden",
   "variable_pair_not_supported": "Dieses Variablenpaar wird von den ausgewählten Börsen nicht unterstützt",
   "verification": "Verifizierung",
   "verify_with_2fa": "Verifizieren Sie mit Cake 2FA",
diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb
index 38e1313f6..42ec77088 100644
--- a/res/values/strings_en.arb
+++ b/res/values/strings_en.arb
@@ -722,6 +722,7 @@
   "use_card_info_two": "Funds are converted to USD when they're held in the prepaid account, not in digital currencies.",
   "use_ssl": "Use SSL",
   "use_suggested": "Use Suggested",
+  "use_testnet": "Use Testnet",
   "variable_pair_not_supported": "This variable pair is not supported with the selected exchanges",
   "verification": "Verification",
   "verify_with_2fa": "Verify with Cake 2FA",
diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb
index 2f3ca878a..455063be5 100644
--- a/res/values/strings_es.arb
+++ b/res/values/strings_es.arb
@@ -723,6 +723,7 @@
   "use_card_info_two": "Los fondos se convierten a USD cuando se mantienen en la cuenta prepaga, no en monedas digitales.",
   "use_ssl": "Utilice SSL",
   "use_suggested": "Usar sugerido",
+  "use_testnet": "Use TestNet",
   "variable_pair_not_supported": "Este par de variables no es compatible con los intercambios seleccionados",
   "verification": "Verificación",
   "verify_with_2fa": "Verificar con Cake 2FA",
diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb
index 0acd685ef..87a8a5e9d 100644
--- a/res/values/strings_fr.arb
+++ b/res/values/strings_fr.arb
@@ -722,6 +722,7 @@
   "use_card_info_two": "Les fonds sont convertis en USD lorsqu'ils sont détenus sur le compte prépayé, et non en devises numériques.",
   "use_ssl": "Utiliser SSL",
   "use_suggested": "Suivre la suggestion",
+  "use_testnet": "Utiliser TestNet",
   "variable_pair_not_supported": "Cette paire variable n'est pas prise en charge avec les échanges sélectionnés",
   "verification": "Vérification",
   "verify_with_2fa": "Vérifier avec Cake 2FA",
diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb
index 92635c6fb..828d86162 100644
--- a/res/values/strings_ha.arb
+++ b/res/values/strings_ha.arb
@@ -724,6 +724,7 @@
   "use_card_info_two": "Ana canza kuɗi zuwa dalar Amurka lokacin da ake riƙe su a cikin asusun da aka riga aka biya, ba cikin agogon dijital ba.",
   "use_ssl": "Yi amfani da SSL",
   "use_suggested": "Amfani da Shawarwari",
+  "use_testnet": "Amfani da gwaji",
   "variable_pair_not_supported": "Ba a samun goyan bayan wannan m biyu tare da zaɓaɓɓun musayar",
   "verification": "tabbatar",
   "verify_with_2fa": "Tabbatar da Cake 2FA",
diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb
index e28fae871..4ad0037d0 100644
--- a/res/values/strings_hi.arb
+++ b/res/values/strings_hi.arb
@@ -724,6 +724,7 @@
   "use_card_info_two": "डिजिटल मुद्राओं में नहीं, प्रीपेड खाते में रखे जाने पर निधियों को यूएसडी में बदल दिया जाता है।",
   "use_ssl": "उपयोग SSL",
   "use_suggested": "सुझाए गए का प्रयोग करें",
+  "use_testnet": "टेस्टनेट का उपयोग करें",
   "variable_pair_not_supported": "यह परिवर्तनीय जोड़ी चयनित एक्सचेंजों के साथ समर्थित नहीं है",
   "verification": "सत्यापन",
   "verify_with_2fa": "केक 2FA के साथ सत्यापित करें",
diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb
index 8dfcaad8e..dd15b623f 100644
--- a/res/values/strings_hr.arb
+++ b/res/values/strings_hr.arb
@@ -722,6 +722,7 @@
   "use_card_info_two": "Sredstva se pretvaraju u USD kada se drže na prepaid računu, a ne u digitalnim valutama.",
   "use_ssl": "Koristi SSL",
   "use_suggested": "Koristite predloženo",
+  "use_testnet": "Koristite TestNet",
   "variable_pair_not_supported": "Ovaj par varijabli nije podržan s odabranim burzama",
   "verification": "Potvrda",
   "verify_with_2fa": "Provjerite s Cake 2FA",
diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb
index a826c536c..04310eec7 100644
--- a/res/values/strings_id.arb
+++ b/res/values/strings_id.arb
@@ -725,6 +725,7 @@
   "use_card_info_two": "Dana dikonversi ke USD ketika disimpan dalam akun pra-bayar, bukan dalam mata uang digital.",
   "use_ssl": "Gunakan SSL",
   "use_suggested": "Gunakan yang Disarankan",
+  "use_testnet": "Gunakan TestNet",
   "variable_pair_not_supported": "Pasangan variabel ini tidak didukung dengan bursa yang dipilih",
   "verification": "Verifikasi",
   "verify_with_2fa": "Verifikasi dengan Cake 2FA",
diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb
index a17718e66..a9af9586b 100644
--- a/res/values/strings_it.arb
+++ b/res/values/strings_it.arb
@@ -724,6 +724,7 @@
   "use_card_info_two": "I fondi vengono convertiti in USD quando sono detenuti nel conto prepagato, non in valute digitali.",
   "use_ssl": "Usa SSL",
   "use_suggested": "Usa suggerito",
+  "use_testnet": "Usa TestNet",
   "variable_pair_not_supported": "Questa coppia di variabili non è supportata con gli scambi selezionati",
   "verification": "Verifica",
   "verify_with_2fa": "Verifica con Cake 2FA",
diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb
index 94f712325..9411c014e 100644
--- a/res/values/strings_ja.arb
+++ b/res/values/strings_ja.arb
@@ -723,6 +723,7 @@
   "use_card_info_two": "デジタル通貨ではなく、プリペイドアカウントで保持されている場合、資金は米ドルに変換されます。",
   "use_ssl": "SSLを使用する",
   "use_suggested": "推奨を使用",
+  "use_testnet": "テストネットを使用します",
   "variable_pair_not_supported": "この変数ペアは、選択した取引所ではサポートされていません",
   "verification": "検証",
   "verify_with_2fa": "Cake 2FA で検証する",
diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb
index 7149d8873..cf1a0fe44 100644
--- a/res/values/strings_ko.arb
+++ b/res/values/strings_ko.arb
@@ -723,6 +723,7 @@
   "use_card_info_two": "디지털 화폐가 아닌 선불 계정에 보유하면 자금이 USD로 변환됩니다.",
   "use_ssl": "SSL 사용",
   "use_suggested": "추천 사용",
+  "use_testnet": "TestNet을 사용하십시오",
   "variable_pair_not_supported": "이 변수 쌍은 선택한 교환에서 지원되지 않습니다.",
   "verification": "검증",
   "verify_with_2fa": "케이크 2FA로 확인",
diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb
index 8c2455290..1553b3347 100644
--- a/res/values/strings_my.arb
+++ b/res/values/strings_my.arb
@@ -722,6 +722,7 @@
   "use_card_info_two": "ဒစ်ဂျစ်တယ်ငွေကြေးများဖြင့်မဟုတ်ဘဲ ကြိုတင်ငွေပေးချေသည့်အကောင့်တွင် သိမ်းထားသည့်အခါ ရန်ပုံငွေများကို USD သို့ ပြောင်းလဲပါသည်။",
   "use_ssl": "SSL ကိုသုံးပါ။",
   "use_suggested": "အကြံပြုထားသည်ကို အသုံးပြုပါ။",
+  "use_testnet": "testnet ကိုသုံးပါ",
   "variable_pair_not_supported": "ရွေးချယ်ထားသော ဖလှယ်မှုများဖြင့် ဤပြောင်းလဲနိုင်သောအတွဲကို ပံ့ပိုးမထားပါ။",
   "verification": "စိစစ်ခြင်း။",
   "verify_with_2fa": "Cake 2FA ဖြင့် စစ်ဆေးပါ။",
diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb
index 3e3a5ffd2..137d6d68f 100644
--- a/res/values/strings_nl.arb
+++ b/res/values/strings_nl.arb
@@ -722,6 +722,7 @@
   "use_card_info_two": "Tegoeden worden omgezet naar USD wanneer ze op de prepaid-rekening staan, niet in digitale valuta.",
   "use_ssl": "Gebruik SSL",
   "use_suggested": "Gebruik aanbevolen",
+  "use_testnet": "Gebruik testnet",
   "variable_pair_not_supported": "Dit variabelenpaar wordt niet ondersteund met de geselecteerde uitwisselingen",
   "verification": "Verificatie",
   "verify_with_2fa": "Controleer met Cake 2FA",
diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb
index dd5a14157..8353252ac 100644
--- a/res/values/strings_pl.arb
+++ b/res/values/strings_pl.arb
@@ -722,6 +722,7 @@
   "use_card_info_two": "Środki są przeliczane na USD, gdy są przechowywane na koncie przedpłaconym, a nie w walutach cyfrowych.",
   "use_ssl": "Użyj SSL",
   "use_suggested": "Użyj sugerowane",
+  "use_testnet": "Użyj testne",
   "variable_pair_not_supported": "Ta para zmiennych nie jest obsługiwana na wybranych giełdach",
   "verification": "Weryfikacja",
   "verify_with_2fa": "Sprawdź za pomocą Cake 2FA",
diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb
index 705dab853..5475b4361 100644
--- a/res/values/strings_pt.arb
+++ b/res/values/strings_pt.arb
@@ -724,6 +724,7 @@
   "use_card_info_two": "Os fundos são convertidos para USD quando mantidos na conta pré-paga, não em moedas digitais.",
   "use_ssl": "Use SSL",
   "use_suggested": "Uso sugerido",
+  "use_testnet": "Use testNet",
   "variable_pair_not_supported": "Este par de variáveis não é compatível com as trocas selecionadas",
   "verification": "Verificação",
   "verify_with_2fa": "Verificar com Cake 2FA",
diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb
index 9adc49596..0b374537e 100644
--- a/res/values/strings_ru.arb
+++ b/res/values/strings_ru.arb
@@ -723,6 +723,7 @@
   "use_card_info_two": "Средства конвертируются в доллары США, когда они хранятся на предоплаченном счете, а не в цифровых валютах.",
   "use_ssl": "Использовать SSL",
   "use_suggested": "Использовать предложенный",
+  "use_testnet": "Используйте Testnet",
   "variable_pair_not_supported": "Эта пара переменных не поддерживается выбранными биржами.",
   "verification": "Проверка",
   "verify_with_2fa": "Подтвердить с помощью Cake 2FA",
diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb
index 5365d4007..db1882f54 100644
--- a/res/values/strings_th.arb
+++ b/res/values/strings_th.arb
@@ -722,6 +722,7 @@
   "use_card_info_two": "เงินจะถูกแปลงค่าเป็นดอลลาร์สหรัฐเมื่อถือไว้ในบัญชีสำรองเงิน ไม่ใช่สกุลเงินดิจิตอล",
   "use_ssl": "ใช้ SSL",
   "use_suggested": "ใช้ที่แนะนำ",
+  "use_testnet": "ใช้ testnet",
   "variable_pair_not_supported": "คู่ความสัมพันธ์ที่เปลี่ยนแปลงได้นี้ไม่สนับสนุนกับหุ้นที่เลือก",
   "verification": "การตรวจสอบ",
   "verify_with_2fa": "ตรวจสอบกับ Cake 2FA",
diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb
index 5a2e103e9..66f210cbf 100644
--- a/res/values/strings_tl.arb
+++ b/res/values/strings_tl.arb
@@ -722,6 +722,7 @@
   "use_card_info_two": "Ang mga pondo ay na -convert sa USD kapag gaganapin sila sa prepaid account, hindi sa mga digital na pera.",
   "use_ssl": "Gumamit ng SSL",
   "use_suggested": "Gumamit ng iminungkahing",
+  "use_testnet": "Gumamit ng testnet",
   "variable_pair_not_supported": "Ang variable na pares na ito ay hindi suportado sa mga napiling palitan",
   "verification": "Pag -verify",
   "verify_with_2fa": "Mag -verify sa cake 2FA",
diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb
index ca9a991a7..c5ca37a48 100644
--- a/res/values/strings_tr.arb
+++ b/res/values/strings_tr.arb
@@ -722,6 +722,7 @@
   "use_card_info_two": "Paralar, dijital para birimlerinde değil, ön ödemeli hesapta tutulduğunda USD'ye dönüştürülür.",
   "use_ssl": "SSL kullan",
   "use_suggested": "Önerileni Kullan",
+  "use_testnet": "TestNet kullanın",
   "variable_pair_not_supported": "Bu değişken paritesi seçilen borsalarda desteklenmemekte",
   "verification": "Doğrulama",
   "verify_with_2fa": "Cake 2FA ile Doğrulayın",
diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb
index 97ff6dda9..9859a0e56 100644
--- a/res/values/strings_uk.arb
+++ b/res/values/strings_uk.arb
@@ -723,6 +723,7 @@
   "use_card_info_two": "Кошти конвертуються в долари США, якщо вони зберігаються на передплаченому рахунку, а не в цифрових валютах.",
   "use_ssl": "Використати SSL",
   "use_suggested": "Використати запропоноване",
+  "use_testnet": "Використовуйте тестову мережу",
   "variable_pair_not_supported": "Ця пара змінних не підтримується вибраними біржами",
   "verification": "Перевірка",
   "verify_with_2fa": "Перевірте за допомогою Cake 2FA",
diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb
index b9bb6ec54..8bce7c895 100644
--- a/res/values/strings_ur.arb
+++ b/res/values/strings_ur.arb
@@ -724,6 +724,7 @@
   "use_card_info_two": "رقوم کو امریکی ڈالر میں تبدیل کیا جاتا ہے جب پری پیڈ اکاؤنٹ میں رکھا جاتا ہے، ڈیجیٹل کرنسیوں میں نہیں۔",
   "use_ssl": "SSL استعمال کریں۔",
   "use_suggested": "تجویز کردہ استعمال کریں۔",
+  "use_testnet": "ٹیسٹ نیٹ استعمال کریں",
   "variable_pair_not_supported": "یہ متغیر جوڑا منتخب ایکسچینجز کے ساتھ تعاون یافتہ نہیں ہے۔",
   "verification": "تصدیق",
   "verify_with_2fa": "کیک 2FA سے تصدیق کریں۔",
diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb
index c5e156f4b..d3d1b590d 100644
--- a/res/values/strings_yo.arb
+++ b/res/values/strings_yo.arb
@@ -723,6 +723,7 @@
   "use_card_info_two": "A pààrọ̀ owó sí owó Amẹ́ríkà tó bá wà nínú àkanti t'á ti fikún tẹ́lẹ̀tẹ́lẹ̀. A kò kó owó náà nínú owó ayélujára.",
   "use_ssl": "Lo SSL",
   "use_suggested": "Lo àbá",
+  "use_testnet": "Lo tele",
   "variable_pair_not_supported": "A kì í ṣe k'á fi àwọn ilé pàṣípààrọ̀ yìí ṣe pàṣípààrọ̀ irú owó méji yìí",
   "verification": "Ìjẹ́rìísí",
   "verify_with_2fa": "Ṣeẹda pẹlu Cake 2FA",
diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb
index 456dd8caa..9c7323948 100644
--- a/res/values/strings_zh.arb
+++ b/res/values/strings_zh.arb
@@ -722,6 +722,7 @@
   "use_card_info_two": "预付账户中的资金转换为美元,不是数字货币。",
   "use_ssl": "使用SSL",
   "use_suggested": "使用建议",
+  "use_testnet": "使用TestNet",
   "variable_pair_not_supported": "所选交易所不支持此变量对",
   "verification": "验证",
   "verify_with_2fa": "用 Cake 2FA 验证",
diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh
index f659239e7..9251ec31a 100644
--- a/scripts/android/app_env.sh
+++ b/scripts/android/app_env.sh
@@ -22,8 +22,8 @@ MONERO_COM_PACKAGE="com.monero.app"
 MONERO_COM_SCHEME="monero.com"
 
 CAKEWALLET_NAME="Cake Wallet"
-CAKEWALLET_VERSION="4.13.3"
-CAKEWALLET_BUILD_NUMBER=192
+CAKEWALLET_VERSION="4.14.0"
+CAKEWALLET_BUILD_NUMBER=193
 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
 CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
 CAKEWALLET_SCHEME="cakewallet"
diff --git a/scripts/android/shell.nix b/scripts/android/shell.nix
new file mode 100644
index 000000000..b89da09c0
--- /dev/null
+++ b/scripts/android/shell.nix
@@ -0,0 +1,16 @@
+{ pkgs ? import <nixpkgs> {} }:
+
+pkgs.mkShell {
+  buildInputs = [
+    pkgs.curl
+    pkgs.unzip
+    pkgs.automake
+    pkgs.file
+    pkgs.pkg-config
+    pkgs.git
+    pkgs.libtool
+    pkgs.ncurses5
+    pkgs.openjdk8
+    pkgs.clang
+  ];
+}
diff --git a/scripts/ios/app_env.sh b/scripts/ios/app_env.sh
index bb4ca77f8..47d80013c 100644
--- a/scripts/ios/app_env.sh
+++ b/scripts/ios/app_env.sh
@@ -18,8 +18,8 @@ MONERO_COM_BUILD_NUMBER=73
 MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
 
 CAKEWALLET_NAME="Cake Wallet"
-CAKEWALLET_VERSION="4.13.3"
-CAKEWALLET_BUILD_NUMBER=212
+CAKEWALLET_VERSION="4.14.0"
+CAKEWALLET_BUILD_NUMBER=213
 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
 
 HAVEN_NAME="Haven"
diff --git a/tool/configure.dart b/tool/configure.dart
index d1516d941..ad0f309aa 100644
--- a/tool/configure.dart
+++ b/tool/configure.dart
@@ -77,6 +77,7 @@ import 'package:cake_wallet/view_model/send/output.dart';
 import 'package:cw_core/wallet_type.dart';
 import 'package:hive/hive.dart';""";
   const bitcoinCWHeaders = """
+import 'package:cw_bitcoin/bitcoin_receive_page_option.dart';
 import 'package:cw_bitcoin/electrum_wallet.dart';
 import 'package:cw_bitcoin/bitcoin_unspent.dart';
 import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
@@ -87,6 +88,7 @@ import 'package:cw_bitcoin/bitcoin_amount_format.dart';
 import 'package:cw_bitcoin/bitcoin_address_record.dart';
 import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
 import 'package:cw_bitcoin/litecoin_wallet_service.dart';
+import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:mobx/mobx.dart';
 """;
   const bitcoinCwPart = "part 'cw_bitcoin.dart';";
@@ -144,6 +146,10 @@ abstract class Bitcoin {
   TransactionPriority getLitecoinTransactionPriorityMedium();
   TransactionPriority getBitcoinTransactionPrioritySlow();
   TransactionPriority getLitecoinTransactionPrioritySlow();
+
+  Future<void> setAddressType(Object wallet, dynamic option);
+  BitcoinReceivePageOption getSelectedAddressType(Object wallet);
+  List<BitcoinReceivePageOption> getBitcoinReceivePageOptions();
 }
   """;