diff --git a/.github/ISSUE_TEMPLATE/bug-report-🪲-.md b/.github/ISSUE_TEMPLATE/bug-report-🪲-.md
new file mode 100644
index 000000000..457cb84a4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-report-🪲-.md
@@ -0,0 +1,33 @@
+---
+name: "Bug Report \U0001FAB2 "
+about: 'Report a bug '
+title: ''
+labels: Bug
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Platform:**
+ - OS: [e.g. iOS 15.1, Android 14]
+ - Device: [e.g. iPhone 14, Galaxy S21]
+ - Cake Wallet Version: [e.g. 4.12.1]
+
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 000000000..d7a1a3ed9
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,8 @@
+blank_issues_enabled: false
+contact_links:
+  - name: Not sure where to start?
+    url: https://guides.cakewallet.com
+    about: Start by reading checking out the guides!
+  - name: Need help?
+    url: https://cakewallet.com/#contact
+    about: Use our live chat or send a support email!
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/feature-or-enhancement-request-✨.md b/.github/ISSUE_TEMPLATE/feature-or-enhancement-request-✨.md
new file mode 100644
index 000000000..20bf2d53f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature-or-enhancement-request-✨.md
@@ -0,0 +1,20 @@
+---
+name: Feature or Enhancement Request ✨
+about: Suggest an idea for Cake Wallet
+title: ''
+labels: Enhancement
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/android/app/build.gradle b/android/app/build.gradle
index e6b9eb2f8..5e27aeb9e 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -37,7 +37,7 @@ if (appPropertiesFile.exists()) {
 }
 
 android {
-    compileSdkVersion 33
+    compileSdkVersion 34
 
     lintOptions {
         disable 'InvalidPackage'
diff --git a/android/app/src/main/AndroidManifestBase.xml b/android/app/src/main/AndroidManifestBase.xml
index f32482e22..2dceca577 100644
--- a/android/app/src/main/AndroidManifestBase.xml
+++ b/android/app/src/main/AndroidManifestBase.xml
@@ -71,8 +71,8 @@
                 android:name="flutterEmbedding"
                 android:value="2" />
         <provider
-            android:name="com.pichillilorenzo.flutter_inappwebview.InAppWebViewFileProvider"
-            android:authorities="${applicationId}.flutter_inappwebview.fileprovider"
+            android:name="com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFileProvider"
+            android:authorities="${applicationId}.flutter_inappwebview_android.fileprovider"
             android:exported="false"
             android:grantUriPermissions="true">
             <meta-data
diff --git a/assets/images/kaspa_icon.png b/assets/images/kaspa_icon.png
new file mode 100644
index 000000000..5201174ef
Binary files /dev/null and b/assets/images/kaspa_icon.png differ
diff --git a/configure_cake_wallet_android.sh b/configure_cake_wallet.sh
similarity index 74%
rename from configure_cake_wallet_android.sh
rename to configure_cake_wallet.sh
index da794a35c..df96c70f6 100755
--- a/configure_cake_wallet_android.sh
+++ b/configure_cake_wallet.sh
@@ -1,4 +1,24 @@
-cd scripts/android
+IOS="ios"
+ANDROID="android"
+
+PLATFORMS=($IOS $ANDROID)
+PLATFORM=$1
+
+if ! [[ " ${PLATFORMS[*]} " =~ " ${PLATFORM} " ]]; then
+    echo "specify platform: ./configure_cake_wallet.sh ios|android"
+    exit 1
+fi
+
+if [ "$PLATFORM" == "$IOS" ]; then
+    echo "Configuring for iOS"
+    cd scripts/ios
+fi
+
+if [ "$PLATFORM" == "$ANDROID" ]; then
+    echo "Configuring for Android"
+    cd scripts/android
+fi
+
 source ./app_env.sh cakewallet
 ./app_config.sh
 cd ../.. && flutter pub get
diff --git a/cw_bitcoin/lib/electrum_balance.dart b/cw_bitcoin/lib/electrum_balance.dart
index a4824db0f..165ea447e 100644
--- a/cw_bitcoin/lib/electrum_balance.dart
+++ b/cw_bitcoin/lib/electrum_balance.dart
@@ -1,13 +1,9 @@
 import 'dart:convert';
-import 'package:flutter/foundation.dart';
 import 'package:cw_bitcoin/bitcoin_amount_format.dart';
 import 'package:cw_core/balance.dart';
 
 class ElectrumBalance extends Balance {
-  const ElectrumBalance(
-      {required this.confirmed,
-      required this.unconfirmed,
-      required this.frozen})
+  const ElectrumBalance({required this.confirmed, required this.unconfirmed, required this.frozen})
       : super(confirmed, unconfirmed);
 
   static ElectrumBalance? fromJSON(String? jsonSource) {
@@ -28,12 +24,10 @@ class ElectrumBalance extends Balance {
   final int frozen;
 
   @override
-  String get formattedAvailableBalance =>
-      bitcoinAmountToString(amount: confirmed - unconfirmed.abs() - frozen);
+  String get formattedAvailableBalance => bitcoinAmountToString(amount: confirmed - frozen);
 
   @override
-  String get formattedAdditionalBalance =>
-      bitcoinAmountToString(amount: unconfirmed);
+  String get formattedAdditionalBalance => bitcoinAmountToString(amount: unconfirmed);
 
   @override
   String get formattedUnAvailableBalance {
@@ -41,6 +35,6 @@ class ElectrumBalance extends Balance {
     return frozenFormatted == '0.0' ? '' : frozenFormatted;
   }
 
-  String toJSON() => json.encode(
-      {'confirmed': confirmed, 'unconfirmed': unconfirmed, 'frozen': frozen});
+  String toJSON() =>
+      json.encode({'confirmed': confirmed, 'unconfirmed': unconfirmed, 'frozen': frozen});
 }
diff --git a/cw_bitcoin/lib/electrum_wallet_addresses.dart b/cw_bitcoin/lib/electrum_wallet_addresses.dart
index ab99a875c..c9e4f8200 100644
--- a/cw_bitcoin/lib/electrum_wallet_addresses.dart
+++ b/cw_bitcoin/lib/electrum_wallet_addresses.dart
@@ -62,6 +62,9 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
     return walletInfo.type == WalletType.bitcoinCash ? toCashAddr(receiveAddress) : receiveAddress;
   }
 
+  @override
+  String get primaryAddress => getAddress(index: 0, hd: mainHd);
+
   @override
   set address(String addr) => null;
 
diff --git a/cw_core/lib/crypto_currency.dart b/cw_core/lib/crypto_currency.dart
index 0f7f25d9b..162ffb1d2 100644
--- a/cw_core/lib/crypto_currency.dart
+++ b/cw_core/lib/crypto_currency.dart
@@ -95,6 +95,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
     CryptoCurrency.banano,
     CryptoCurrency.usdtPoly,
     CryptoCurrency.usdcEPoly,
+    CryptoCurrency.kaspa,
   ];
 
   static const havenCurrencies = [
@@ -206,6 +207,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
   static const banano = CryptoCurrency(title: 'BAN', fullName: 'Banano', raw: 86, name: 'banano', iconPath: 'assets/images/nano_icon.png', decimals: 29);
   static const usdtPoly = CryptoCurrency(title: 'USDT', tag: 'POLY', fullName: 'Tether USD (PoS)', raw: 87, name: 'usdtpoly', iconPath: 'assets/images/usdt_icon.png', decimals: 6);
   static const usdcEPoly = CryptoCurrency(title: 'USDC.E', tag: 'POLY', fullName: 'USD Coin (PoS)', raw: 88, name: 'usdcepoly', iconPath: 'assets/images/usdc_icon.png', decimals: 6);
+  static const kaspa = CryptoCurrency(title: 'KAS', fullName: 'Kaspa', raw: 89, name: 'kaspa', iconPath: 'assets/images/kaspa_icon.png', decimals: 8);
 
 
   static final Map<int, CryptoCurrency> _rawCurrencyMap =
diff --git a/cw_core/lib/transaction_info.dart b/cw_core/lib/transaction_info.dart
index 38b4b799d..7624b147f 100644
--- a/cw_core/lib/transaction_info.dart
+++ b/cw_core/lib/transaction_info.dart
@@ -15,6 +15,7 @@ abstract class TransactionInfo extends Object with Keyable {
   String? feeFormatted();
   void changeFiatAmount(String amount);
   String? to;
+  String? from;
 
   @override
   dynamic get keyIndex => id;
diff --git a/cw_core/lib/wallet_addresses.dart b/cw_core/lib/wallet_addresses.dart
index 632eb1332..d8c84c80c 100644
--- a/cw_core/lib/wallet_addresses.dart
+++ b/cw_core/lib/wallet_addresses.dart
@@ -10,6 +10,8 @@ abstract class WalletAddresses {
 
   String get address;
 
+  String? get primaryAddress => null;
+
   set address(String address);
 
   Map<String, String> addressesMap;
diff --git a/cw_nano/lib/banano_balance.dart b/cw_nano/lib/banano_balance.dart
index b85609b60..b904a35cb 100644
--- a/cw_nano/lib/banano_balance.dart
+++ b/cw_nano/lib/banano_balance.dart
@@ -1,20 +1,19 @@
 import 'package:cw_core/balance.dart';
-import 'package:cw_nano/nano_util.dart';
+import 'package:nanoutil/nanoutil.dart';
 
 class BananoBalance extends Balance {
   final BigInt currentBalance;
   final BigInt receivableBalance;
 
-  BananoBalance({required this.currentBalance, required this.receivableBalance}) : super(0, 0) {
-  }
+  BananoBalance({required this.currentBalance, required this.receivableBalance}) : super(0, 0);
 
   @override
   String get formattedAvailableBalance {
-    return NanoUtil.getRawAsUsableString(currentBalance.toString(), NanoUtil.rawPerBanano);
+    return NanoAmounts.getRawAsUsableString(currentBalance.toString(), NanoAmounts.rawPerBanano);
   }
 
   @override
   String get formattedAdditionalBalance {
-    return NanoUtil.getRawAsUsableString(receivableBalance.toString(), NanoUtil.rawPerBanano);
+    return NanoAmounts.getRawAsUsableString(receivableBalance.toString(), NanoAmounts.rawPerBanano);
   }
 }
diff --git a/cw_nano/lib/nano_balance.dart b/cw_nano/lib/nano_balance.dart
index dbb39d2a3..8b8c93b33 100644
--- a/cw_nano/lib/nano_balance.dart
+++ b/cw_nano/lib/nano_balance.dart
@@ -1,34 +1,35 @@
 import 'package:cw_core/balance.dart';
-import 'package:cw_nano/nano_util.dart';
+import 'package:nanoutil/nanoutil.dart';
 
 BigInt stringAmountToBigInt(String amount) {
-  return BigInt.parse(NanoUtil.getAmountAsRaw(amount, NanoUtil.rawPerNano));
+  return BigInt.parse(NanoAmounts.getAmountAsRaw(amount, NanoAmounts.rawPerNano));
 }
 
 class NanoBalance extends Balance {
   final BigInt currentBalance;
   final BigInt receivableBalance;
-  late String formattedCurrentBalance;
-  late String formattedReceivableBalance;
 
-  NanoBalance({required this.currentBalance, required this.receivableBalance}) : super(0, 0) {
-    this.formattedCurrentBalance = "";
-    this.formattedReceivableBalance = "";
-  }
+  NanoBalance({required this.currentBalance, required this.receivableBalance}) : super(0, 0);
 
-  NanoBalance.fromString(
-      {required this.formattedCurrentBalance, required this.formattedReceivableBalance})
+  NanoBalance.fromFormattedString(
+      {required String formattedCurrentBalance, required String formattedReceivableBalance})
       : currentBalance = stringAmountToBigInt(formattedCurrentBalance),
         receivableBalance = stringAmountToBigInt(formattedReceivableBalance),
         super(0, 0);
 
+  NanoBalance.fromRawString(
+      {required String currentBalance, required String receivableBalance})
+      : currentBalance = BigInt.parse(currentBalance),
+        receivableBalance = BigInt.parse(receivableBalance),
+        super(0, 0);
+
   @override
   String get formattedAvailableBalance {
-    return NanoUtil.getRawAsUsableString(currentBalance.toString(), NanoUtil.rawPerNano);
+    return NanoAmounts.getRawAsUsableString(currentBalance.toString(), NanoAmounts.rawPerNano);
   }
 
   @override
   String get formattedAdditionalBalance {
-    return NanoUtil.getRawAsUsableString(receivableBalance.toString(), NanoUtil.rawPerNano);
+    return NanoAmounts.getRawAsUsableString(receivableBalance.toString(), NanoAmounts.rawPerNano);
   }
 }
diff --git a/cw_nano/lib/nano_client.dart b/cw_nano/lib/nano_client.dart
index f1d08204a..661fbcab8 100644
--- a/cw_nano/lib/nano_client.dart
+++ b/cw_nano/lib/nano_client.dart
@@ -4,10 +4,10 @@ import 'dart:convert';
 import 'package:cw_core/nano_account_info_response.dart';
 import 'package:cw_nano/nano_balance.dart';
 import 'package:cw_nano/nano_transaction_model.dart';
-import 'package:cw_nano/nano_util.dart';
 import 'package:http/http.dart' as http;
 import 'package:nanodart/nanodart.dart';
 import 'package:cw_core/node.dart';
+import 'package:nanoutil/nanoutil.dart';
 import 'package:shared_preferences/shared_preferences.dart';
 
 class NanoClient {
@@ -61,6 +61,13 @@ class NanoClient {
       ),
     );
     final data = await jsonDecode(response.body);
+    if (response.statusCode != 200 ||
+        data["error"] != null ||
+        data["balance"] == null ||
+        data["receivable"] == null) {
+      throw Exception(
+          "Error while trying to get balance! ${data["error"] != null ? data["error"] : ""}");
+    }
     final String currentBalance = data["balance"] as String;
     final String receivableBalance = data["receivable"] as String;
     final BigInt cur = BigInt.parse(currentBalance);
@@ -203,7 +210,7 @@ class NanoClient {
     String? previousHash,
   }) async {
     // our address:
-    final String publicAddress = NanoUtil.privateKeyToAddress(privateKey);
+    final String publicAddress = NanoDerivations.privateKeyToAddress(privateKey);
 
     // first get the current account balance:
     if (balanceAfterTx == null) {
diff --git a/cw_nano/lib/nano_transaction_info.dart b/cw_nano/lib/nano_transaction_info.dart
index 8958086dd..9195a06ef 100644
--- a/cw_nano/lib/nano_transaction_info.dart
+++ b/cw_nano/lib/nano_transaction_info.dart
@@ -1,7 +1,7 @@
 import 'package:cw_core/format_amount.dart';
 import 'package:cw_core/transaction_direction.dart';
 import 'package:cw_core/transaction_info.dart';
-import 'package:cw_nano/nano_util.dart';
+import 'package:nanoutil/nanoutil.dart';
 
 class NanoTransactionInfo extends TransactionInfo {
   NanoTransactionInfo({
@@ -13,6 +13,8 @@ class NanoTransactionInfo extends TransactionInfo {
     required this.confirmed,
     required this.date,
     required this.confirmations,
+    required this.to,
+    required this.from,
   }) : this.amount = amountRaw.toInt();
 
   final String id;
@@ -24,14 +26,17 @@ class NanoTransactionInfo extends TransactionInfo {
   final bool confirmed;
   final int confirmations;
   final String tokenSymbol;
+  final String? to;
+  final String? from;
   String? _fiatAmount;
 
   bool get isPending => !this.confirmed;
 
   @override
   String amountFormatted() {
-    final String amt = NanoUtil.getRawAsUsableString(amountRaw.toString(), NanoUtil.rawPerNano);
-    final String acc = NanoUtil.getRawAccuracy(amountRaw.toString(), NanoUtil.rawPerNano);
+    final String amt =
+        NanoAmounts.getRawAsUsableString(amountRaw.toString(), NanoAmounts.rawPerNano);
+    final String acc = NanoAmounts.getRawAccuracy(amountRaw.toString(), NanoAmounts.rawPerNano);
     return "$acc$amt $tokenSymbol";
   }
 
@@ -54,6 +59,8 @@ class NanoTransactionInfo extends TransactionInfo {
       confirmed: data['confirmed'] as bool,
       confirmations: data['confirmations'] as int,
       tokenSymbol: data['tokenSymbol'] as String,
+      to: data['to'] as String,
+      from: data['from'] as String,
     );
   }
 
@@ -66,5 +73,7 @@ class NanoTransactionInfo extends TransactionInfo {
         'confirmed': confirmed,
         'confirmations': confirmations,
         'tokenSymbol': tokenSymbol,
+        'to': to,
+        'from': from,
       };
 }
diff --git a/cw_nano/lib/nano_util.dart b/cw_nano/lib/nano_util.dart
deleted file mode 100644
index 13d6f5649..000000000
--- a/cw_nano/lib/nano_util.dart
+++ /dev/null
@@ -1,193 +0,0 @@
-import 'dart:convert';
-import 'dart:typed_data';
-
-import 'package:convert/convert.dart';
-import "package:ed25519_hd_key/ed25519_hd_key.dart";
-import 'package:libcrypto/libcrypto.dart';
-import 'package:nanodart/nanodart.dart';
-import 'package:decimal/decimal.dart';
-
-class NanoUtil {
-  // standard:
-  static String seedToPrivate(String seed, int index) {
-    return NanoKeys.seedToPrivate(seed, index);
-  }
-
-  static String seedToAddress(String seed, int index) {
-    return NanoAccounts.createAccount(
-        NanoAccountType.NANO, privateKeyToPublic(seedToPrivate(seed, index)));
-  }
-
-  static String seedToMnemonic(String seed) {
-    return NanoMnemomics.seedToMnemonic(seed).join(" ");
-  }
-
-  static Future<String> mnemonicToSeed(String mnemonic) async {
-    return NanoMnemomics.mnemonicListToSeed(mnemonic.split(' '));
-  }
-
-  static String privateKeyToPublic(String privateKey) {
-    // return NanoHelpers.byteToHex(Ed25519Blake2b.getPubkey(NanoHelpers.hexToBytes(privateKey))!);
-    return NanoKeys.createPublicKey(privateKey);
-  }
-
-  static String addressToPublicKey(String publicAddress) {
-    return NanoAccounts.extractPublicKey(publicAddress);
-  }
-
-  // universal:
-  static String privateKeyToAddress(String privateKey) {
-    return NanoAccounts.createAccount(NanoAccountType.NANO, privateKeyToPublic(privateKey));
-  }
-
-  static String publicKeyToAddress(String publicKey) {
-    return NanoAccounts.createAccount(NanoAccountType.NANO, publicKey);
-  }
-
-  // standard + hd:
-  static bool isValidSeed(String seed) {
-    // Ensure seed is 64 or 128 characters long
-    if (seed == null || (seed.length != 64 && seed.length != 128)) {
-      return false;
-    }
-    // Ensure seed only contains hex characters, 0-9;A-F
-    return NanoHelpers.isHexString(seed);
-  }
-
-  // // hd:
-  static Future<String> hdMnemonicListToSeed(List<String> words) async {
-    // if (words.length != 24) {
-    //   throw Exception('Expected a 24-word list, got a ${words.length} list');
-    // }
-    final Uint8List salt = Uint8List.fromList(utf8.encode('mnemonic'));
-    final Pbkdf2 hasher = Pbkdf2(iterations: 2048);
-    final String seed = await hasher.sha512(words.join(' '), salt);
-    return seed;
-  }
-
-  static Future<String> hdSeedToPrivate(String seed, int index) async {
-    List<int> seedBytes = hex.decode(seed);
-    KeyData data = await ED25519_HD_KEY.derivePath("m/44'/165'/$index'", seedBytes);
-    return hex.encode(data.key);
-  }
-
-  static Future<String> hdSeedToAddress(String seed, int index) async {
-    return NanoAccounts.createAccount(
-        NanoAccountType.NANO, privateKeyToPublic(await hdSeedToPrivate(seed, index)));
-  }
-
-  static Future<String> uniSeedToAddress(String seed, int index, String type) {
-    if (type == "standard") {
-      return Future<String>.value(seedToAddress(seed, index));
-    } else if (type == "hd") {
-      return hdSeedToAddress(seed, index);
-    } else {
-      throw Exception('Unknown seed type');
-    }
-  }
-
-  static Future<String> uniSeedToPrivate(String seed, int index, String type) {
-    if (type == "standard") {
-      return Future<String>.value(seedToPrivate(seed, index));
-    } else if (type == "hd") {
-      return hdSeedToPrivate(seed, index);
-    } else {
-      throw Exception('Unknown seed type');
-    }
-  }
-
-  static bool isValidBip39Seed(String seed) {
-    // Ensure seed is 128 characters long
-    if (seed.length != 128) {
-      return false;
-    }
-    // Ensure seed only contains hex characters, 0-9;A-F
-    return NanoHelpers.isHexString(seed);
-  }
-
-  // number util:
-
-  static const int maxDecimalDigits = 6; // Max digits after decimal
-  static BigInt rawPerNano = BigInt.parse("1000000000000000000000000000000");
-  static BigInt rawPerNyano = BigInt.parse("1000000000000000000000000");
-  static BigInt rawPerBanano = BigInt.parse("100000000000000000000000000000");
-  static BigInt rawPerXMR = BigInt.parse("1000000000000");
-  static BigInt convertXMRtoNano = BigInt.parse("1000000000000000000");
-  // static BigInt convertXMRtoNano = BigInt.parse("1000000000000000000000000000");
-
-  /// Convert raw to ban and return as BigDecimal
-  ///
-  /// @param raw 100000000000000000000000000000
-  /// @return Decimal value 1.000000000000000000000000000000
-  ///
-  static Decimal getRawAsDecimal(String? raw, BigInt? rawPerCur) {
-    rawPerCur ??= rawPerNano;
-    final Decimal amount = Decimal.parse(raw.toString());
-    final Decimal result = (amount / Decimal.parse(rawPerCur.toString())).toDecimal();
-    return result;
-  }
-
-  static String truncateDecimal(Decimal input, {int digits = maxDecimalDigits}) {
-    Decimal bigger = input.shift(digits);
-    bigger = bigger.floor(); // chop off the decimal: 1.059 -> 1.05
-    bigger = bigger.shift(-digits);
-    return bigger.toString();
-  }
-
-  /// Return raw as a NANO amount.
-  ///
-  /// @param raw 100000000000000000000000000000
-  /// @returns 1
-  ///
-  static String getRawAsUsableString(String? raw, BigInt rawPerCur) {
-    final String res =
-        truncateDecimal(getRawAsDecimal(raw, rawPerCur), digits: maxDecimalDigits + 9);
-
-    if (raw == null || raw == "0" || raw == "00000000000000000000000000000000") {
-      return "0";
-    }
-
-    if (!res.contains(".")) {
-      return res;
-    }
-
-    final String numAmount = res.split(".")[0];
-    String decAmount = res.split(".")[1];
-
-    // truncate:
-    if (decAmount.length > maxDecimalDigits) {
-      decAmount = decAmount.substring(0, maxDecimalDigits);
-      // remove trailing zeros:
-      decAmount = decAmount.replaceAllMapped(RegExp(r'0+$'), (Match match) => '');
-      if (decAmount.isEmpty) {
-        return numAmount;
-      }
-    }
-
-    return "$numAmount.$decAmount";
-  }
-
-  static String getRawAccuracy(String? raw, BigInt rawPerCur) {
-    final String rawString = getRawAsUsableString(raw, rawPerCur);
-    final String rawDecimalString = getRawAsDecimal(raw, rawPerCur).toString();
-
-    if (raw == null || raw.isEmpty || raw == "0") {
-      return "";
-    }
-
-    if (rawString != rawDecimalString) {
-      return "~";
-    }
-    return "";
-  }
-
-  /// Return readable string amount as raw string
-  /// @param amount 1.01
-  /// @returns  101000000000000000000000000000
-  ///
-  static String getAmountAsRaw(String amount, BigInt rawPerCur) {
-    final Decimal asDecimal = Decimal.parse(amount);
-    final Decimal rawDecimal = Decimal.parse(rawPerCur.toString());
-    return (asDecimal * rawDecimal).toString();
-  }
-}
diff --git a/cw_nano/lib/nano_wallet.dart b/cw_nano/lib/nano_wallet.dart
index b0d98efec..1f6ec36ae 100644
--- a/cw_nano/lib/nano_wallet.dart
+++ b/cw_nano/lib/nano_wallet.dart
@@ -18,7 +18,6 @@ import 'package:cw_nano/nano_client.dart';
 import 'package:cw_nano/nano_transaction_credentials.dart';
 import 'package:cw_nano/nano_transaction_history.dart';
 import 'package:cw_nano/nano_transaction_info.dart';
-import 'package:cw_nano/nano_util.dart';
 import 'package:cw_nano/nano_wallet_keys.dart';
 import 'package:cw_nano/pending_nano_transaction.dart';
 import 'package:mobx/mobx.dart';
@@ -27,6 +26,7 @@ import 'package:cw_nano/nano_wallet_addresses.dart';
 import 'package:cw_core/wallet_base.dart';
 import 'package:nanodart/nanodart.dart';
 import 'package:bip39/bip39.dart' as bip39;
+import 'package:nanoutil/nanoutil.dart';
 
 part 'nano_wallet.g.dart';
 
@@ -83,6 +83,8 @@ abstract class NanoWalletBase
   @observable
   late ObservableMap<CryptoCurrency, NanoBalance> balance;
 
+  static const int POLL_INTERVAL_SECONDS = 10;
+
   // initialize the different forms of private / public key we'll need:
   Future<void> init() async {
     if (_derivationType == DerivationType.unknown) {
@@ -100,11 +102,21 @@ abstract class NanoWalletBase
       if (_derivationType == DerivationType.nano) {
         _hexSeed = bip39.mnemonicToEntropy(_mnemonic).toUpperCase();
       } else {
-        _hexSeed = await NanoUtil.hdMnemonicListToSeed(_mnemonic.split(' '));
+        _hexSeed = await NanoDerivations.hdMnemonicListToSeed(_mnemonic.split(' '));
       }
     }
-    _privateKey = await NanoUtil.uniSeedToPrivate(_hexSeed!, 0, type);
-    _publicAddress = await NanoUtil.uniSeedToAddress(_hexSeed!, 0, type);
+    NanoDerivationType derivationType =
+        type == "standard" ? NanoDerivationType.STANDARD : NanoDerivationType.HD;
+    _privateKey = await NanoDerivations.universalSeedToPrivate(
+      _hexSeed!,
+      index: 0,
+      type: derivationType,
+    );
+    _publicAddress = await NanoDerivations.universalSeedToAddress(
+      _hexSeed!,
+      index: 0,
+      type: derivationType,
+    );
     this.walletInfo.address = _publicAddress!;
 
     await walletAddresses.init();
@@ -125,6 +137,7 @@ abstract class NanoWalletBase
   @override
   void close() {
     _client.stop();
+    _receiveTimer?.cancel();
   }
 
   @action
@@ -139,6 +152,7 @@ abstract class NanoWalletBase
 
       try {
         await _updateBalance();
+        await updateTransactions();
         await _updateRep();
         await _receiveAll();
       } catch (e) {
@@ -173,8 +187,8 @@ abstract class NanoWalletBase
       if (txOut.sendAll) {
         amt = balance[currency]?.currentBalance ?? BigInt.zero;
       } else {
-        amt = BigInt.tryParse(NanoUtil.getAmountAsRaw(
-                txOut.cryptoAmount?.replaceAll(',', '.') ?? "0", NanoUtil.rawPerNano)) ??
+        amt = BigInt.tryParse(NanoAmounts.getAmountAsRaw(
+                txOut.cryptoAmount?.replaceAll(',', '.') ?? "0", NanoAmounts.rawPerNano)) ??
             BigInt.zero;
       }
 
@@ -186,9 +200,7 @@ abstract class NanoWalletBase
 
       final block = await _client.constructSendBlock(
         amountRaw: amt.toString(),
-        destinationAddress: txOut.isParsedAddress
-            ? txOut.extractedAddress!
-            : txOut.address,
+        destinationAddress: txOut.isParsedAddress ? txOut.extractedAddress! : txOut.address,
         privateKey: _privateKey!,
         balanceAfterTx: runningBalance,
         previousHash: previousHash,
@@ -236,10 +248,10 @@ abstract class NanoWalletBase
     }
   }
 
-  Future<void> updateTransactions() async {
+  Future<bool> updateTransactions() async {
     try {
       if (_isTransactionUpdating) {
-        return;
+        return false;
       }
 
       _isTransactionUpdating = true;
@@ -247,8 +259,10 @@ abstract class NanoWalletBase
       transactionHistory.addMany(transactions);
       await transactionHistory.save();
       _isTransactionUpdating = false;
+      return true;
     } catch (_) {
       _isTransactionUpdating = false;
+      return false;
     }
   }
 
@@ -261,16 +275,17 @@ abstract class NanoWalletBase
     final Map<String, NanoTransactionInfo> result = {};
 
     for (var transactionModel in transactions) {
+      final bool isSend = transactionModel.type == "send";
       result[transactionModel.hash] = NanoTransactionInfo(
         id: transactionModel.hash,
         amountRaw: transactionModel.amount,
         height: transactionModel.height,
-        direction: transactionModel.type == "send"
-            ? TransactionDirection.outgoing
-            : TransactionDirection.incoming,
+        direction: isSend ? TransactionDirection.outgoing : TransactionDirection.incoming,
         confirmed: transactionModel.confirmed,
         date: transactionModel.date ?? DateTime.now(),
         confirmations: transactionModel.confirmed ? 1 : 0,
+        to: isSend ? transactionModel.account : address,
+        from: isSend ? address : transactionModel.account,
       );
     }
 
@@ -312,11 +327,10 @@ abstract class NanoWalletBase
   Future<void> startSync() async {
     try {
       syncStatus = AttemptingSyncStatus();
-      await _updateBalance();
-      await updateTransactions();
 
+      // setup a timer to receive transactions periodically:
       _receiveTimer?.cancel();
-      _receiveTimer = Timer.periodic(const Duration(seconds: 15), (timer) async {
+      _receiveTimer = Timer.periodic(const Duration(seconds: POLL_INTERVAL_SECONDS), (timer) async {
         // get our balance:
         await _updateBalance();
         // if we have anything to receive, process it:
@@ -325,6 +339,14 @@ abstract class NanoWalletBase
         }
       });
 
+      // also run once, immediately:
+      await _updateBalance();
+      bool updateSuccess = await updateTransactions();
+      if (!updateSuccess) {
+        syncStatus = FailedSyncStatus();
+        return;
+      }
+
       syncStatus = SyncedSyncStatus();
     } catch (e) {
       print(e);
@@ -353,9 +375,11 @@ abstract class NanoWalletBase
 
     final data = json.decode(jsonSource) as Map;
     final mnemonic = data['mnemonic'] as String;
-    final balance = NanoBalance.fromString(
-        formattedCurrentBalance: data['currentBalance'] as String? ?? "0",
-        formattedReceivableBalance: data['receivableBalance'] as String? ?? "0");
+    
+    final balance = NanoBalance.fromRawString(
+      currentBalance: data['currentBalance'] as String? ?? "0",
+      receivableBalance: data['receivableBalance'] as String? ?? "0",
+    );
 
     DerivationType derivationType = DerivationType.nano;
     if (data['derivationType'] == "DerivationType.bip39") {
@@ -374,12 +398,26 @@ abstract class NanoWalletBase
   }
 
   Future<void> _updateBalance() async {
+    var oldBalance = balance[currency];
     try {
       balance[currency] = await _client.getBalance(_publicAddress!);
     } catch (e) {
       print("Failed to get balance $e");
+      // if we don't have a balance, we should at least create one, since it's a late binding
+      // otherwise, it's better to just leave it as whatever it was before:
+      if (balance[currency] == null) {
+        balance[currency] =
+            NanoBalance(currentBalance: BigInt.zero, receivableBalance: BigInt.zero);
+      }
+    }
+    // don't save unnecessarily:
+    // trying to save too frequently can cause problems with the file system
+    // since nano is updated frequently this can be a problem, so we only save if there is a change:
+    if (oldBalance == null ||
+        balance[currency]!.currentBalance != oldBalance.currentBalance ||
+        balance[currency]!.receivableBalance != oldBalance.receivableBalance) {
+      await save();
     }
-    await save();
   }
 
   Future<void> _updateRep() async {
@@ -394,11 +432,19 @@ abstract class NanoWalletBase
   }
 
   Future<void> regenerateAddress() async {
-    final String type = (_derivationType == DerivationType.nano) ? "standard" : "hd";
-    _privateKey =
-        await NanoUtil.uniSeedToPrivate(_hexSeed!, this.walletAddresses.account!.id, type);
-    _publicAddress =
-        await NanoUtil.uniSeedToAddress(_hexSeed!, this.walletAddresses.account!.id, type);
+    final NanoDerivationType type = (_derivationType == DerivationType.nano)
+        ? NanoDerivationType.STANDARD
+        : NanoDerivationType.HD;
+    _privateKey = await NanoDerivations.universalSeedToPrivate(
+      _hexSeed!,
+      index: this.walletAddresses.account!.id,
+      type: type,
+    );
+    _publicAddress = await NanoDerivations.universalSeedToAddress(
+      _hexSeed!,
+      index: this.walletAddresses.account!.id,
+      type: type,
+    );
 
     this.walletInfo.address = _publicAddress!;
     this.walletAddresses.address = _publicAddress!;
diff --git a/cw_nano/lib/nano_wallet_service.dart b/cw_nano/lib/nano_wallet_service.dart
index 2f183d1cc..7a66f8c9f 100644
--- a/cw_nano/lib/nano_wallet_service.dart
+++ b/cw_nano/lib/nano_wallet_service.dart
@@ -6,12 +6,12 @@ import 'package:cw_core/wallet_info.dart';
 import 'package:cw_core/wallet_service.dart';
 import 'package:cw_core/wallet_type.dart';
 import 'package:cw_nano/nano_mnemonic.dart' as nm;
-import 'package:cw_nano/nano_util.dart';
 import 'package:cw_nano/nano_wallet.dart';
 import 'package:cw_nano/nano_wallet_creation_credentials.dart';
 import 'package:hive/hive.dart';
 import 'package:bip39/bip39.dart' as bip39;
 import 'package:nanodart/nanodart.dart';
+import 'package:nanoutil/nanoutil.dart';
 
 class NanoWalletService extends WalletService<NanoNewWalletCredentials,
     NanoRestoreWalletFromSeedCredentials, NanoRestoreWalletFromKeysCredentials> {
@@ -30,7 +30,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
     // nano standard:
     DerivationType derivationType = DerivationType.nano;
     String seedKey = NanoSeeds.generateSeed();
-    String mnemonic = NanoUtil.seedToMnemonic(seedKey);
+    String mnemonic = NanoDerivations.standardSeedToMnemonic(seedKey);
 
     credentials.walletInfo!.derivationType = derivationType;
 
@@ -95,7 +95,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
     // we can't derive the mnemonic from the key in all cases, only if it's a "nano" seed
     if (credentials.seedKey.length == 64) {
       try {
-        mnemonic = NanoUtil.seedToMnemonic(credentials.seedKey);
+        mnemonic = NanoDerivations.standardSeedToMnemonic(credentials.seedKey);
       } catch (e) {
         throw Exception("Wasn't a valid nano style seed!");
       }
diff --git a/cw_nano/lib/pending_nano_transaction.dart b/cw_nano/lib/pending_nano_transaction.dart
index 727f02534..a027100fd 100644
--- a/cw_nano/lib/pending_nano_transaction.dart
+++ b/cw_nano/lib/pending_nano_transaction.dart
@@ -1,6 +1,6 @@
 import 'package:cw_core/pending_transaction.dart';
 import 'package:cw_nano/nano_client.dart';
-import 'package:cw_nano/nano_util.dart';
+import 'package:nanoutil/nanoutil.dart';
 
 class PendingNanoTransaction with PendingTransaction {
   PendingNanoTransaction({
@@ -18,13 +18,13 @@ class PendingNanoTransaction with PendingTransaction {
 
   @override
   String get amountFormatted {
-    final String amt = NanoUtil.getRawAsUsableString(amount.toString(), NanoUtil.rawPerNano);
+    final String amt = NanoAmounts.getRawAsUsableString(amount.toString(), NanoAmounts.rawPerNano);
     return amt;
   }
 
   String get accurateAmountFormatted {
-    final String amt = NanoUtil.getRawAsUsableString(amount.toString(), NanoUtil.rawPerNano);
-    final String acc = NanoUtil.getRawAccuracy(amount.toString(), NanoUtil.rawPerNano);
+    final String amt = NanoAmounts.getRawAsUsableString(amount.toString(), NanoAmounts.rawPerNano);
+    final String acc = NanoAmounts.getRawAccuracy(amount.toString(), NanoAmounts.rawPerNano);
     return "$acc$amt";
   }
 
diff --git a/cw_nano/pubspec.yaml b/cw_nano/pubspec.yaml
index f06177d3c..a4b8732fd 100644
--- a/cw_nano/pubspec.yaml
+++ b/cw_nano/pubspec.yaml
@@ -22,6 +22,10 @@ dependencies:
   hex: ^0.2.0
   http: ^1.1.0
   shared_preferences: ^2.0.15
+  nanoutil:
+    git:
+      url: https://github.com/perishllc/nanoutil.git
+      ref: c37e72817cf0a28162f43124f79661d6c8e0098f
   cw_core:
     path: ../cw_core
 
diff --git a/lib/buy/dfx/dfx_buy_provider.dart b/lib/buy/dfx/dfx_buy_provider.dart
index f74039caa..78a5277ce 100644
--- a/lib/buy/dfx/dfx_buy_provider.dart
+++ b/lib/buy/dfx/dfx_buy_provider.dart
@@ -66,8 +66,10 @@ class DFXBuyProvider extends BuyProvider {
     }
   }
 
+  String get walletAddress =>
+      wallet.walletAddresses.primaryAddress ?? wallet.walletAddresses.address;
+
   Future<String> getSignMessage() async {
-    final walletAddress = wallet.walletAddresses.address;
     final uri = Uri.https(_baseUrl, _authPath, {'address': walletAddress});
 
     var response = await http.get(uri, headers: {'accept': 'application/json'});
@@ -83,7 +85,6 @@ class DFXBuyProvider extends BuyProvider {
 
   Future<String> signUp() async {
     final signMessage = getSignature(await getSignMessage());
-    final walletAddress = wallet.walletAddresses.address;
 
     final requestBody = jsonEncode({
       'wallet': walletName,
@@ -92,8 +93,11 @@ class DFXBuyProvider extends BuyProvider {
     });
 
     final uri = Uri.https(_baseUrl, _signUpPath);
-    var response = await http.post(uri,
-        headers: {'Content-Type': 'application/json'}, body: requestBody);
+    var response = await http.post(
+      uri,
+      headers: {'Content-Type': 'application/json'},
+      body: requestBody,
+    );
 
     if (response.statusCode == 201) {
       final responseBody = jsonDecode(response.body);
@@ -103,14 +107,12 @@ class DFXBuyProvider extends BuyProvider {
       final message = responseBody['message'] ?? 'Service unavailable in your country';
       throw Exception(message);
     } else {
-      throw Exception(
-          'Failed to sign up. Status: ${response.statusCode} ${response.body}');
+      throw Exception('Failed to sign up. Status: ${response.statusCode} ${response.body}');
     }
   }
 
   Future<String> signIn() async {
     final signMessage = getSignature(await getSignMessage());
-    final walletAddress = wallet.walletAddresses.address;
 
     final requestBody = jsonEncode({
       'address': walletAddress,
@@ -118,8 +120,11 @@ class DFXBuyProvider extends BuyProvider {
     });
 
     final uri = Uri.https(_baseUrl, _signInPath);
-    var response = await http.post(uri,
-        headers: {'Content-Type': 'application/json'}, body: requestBody);
+    var response = await http.post(
+      uri,
+      headers: {'Content-Type': 'application/json'},
+      body: requestBody,
+    );
 
     if (response.statusCode == 201) {
       final responseBody = jsonDecode(response.body);
@@ -129,8 +134,7 @@ class DFXBuyProvider extends BuyProvider {
       final message = responseBody['message'] ?? 'Service unavailable in your country';
       throw Exception(message);
     } else {
-      throw Exception(
-          'Failed to sign in. Status: ${response.statusCode} ${response.body}');
+      throw Exception('Failed to sign in. Status: ${response.statusCode} ${response.body}');
     }
   }
 
@@ -142,8 +146,7 @@ class DFXBuyProvider extends BuyProvider {
       case WalletType.litecoin:
       case WalletType.bitcoin:
       case WalletType.bitcoinCash:
-        return wallet.signMessage(message,
-            address: wallet.walletAddresses.address);
+        return wallet.signMessage(message, address: walletAddress);
       default:
         throw Exception("WalletType is not available for DFX ${wallet.type}");
     }
@@ -178,8 +181,7 @@ class DFXBuyProvider extends BuyProvider {
 
       if (await canLaunchUrl(uri)) {
         if (DeviceInfo.instance.isMobile) {
-          Navigator.of(context)
-              .pushNamed(Routes.webViewPage, arguments: ["DFX Connect", uri]);
+          Navigator.of(context).pushNamed(Routes.webViewPage, arguments: [title, uri]);
         } else {
           await launchUrl(uri, mode: LaunchMode.externalApplication);
         }
diff --git a/lib/buy/onramper/onramper_buy_provider.dart b/lib/buy/onramper/onramper_buy_provider.dart
index 014edb813..3819f074d 100644
--- a/lib/buy/onramper/onramper_buy_provider.dart
+++ b/lib/buy/onramper/onramper_buy_provider.dart
@@ -52,7 +52,7 @@ class OnRamperBuyProvider extends BuyProvider {
     return color.value.toRadixString(16).replaceAll(RegExp(r'^ff'), "");
   }
 
-  Uri requestOnramperUrl(BuildContext context) {
+  Uri requestOnramperUrl(BuildContext context, bool? isBuyAction) {
     String primaryColor,
         secondaryColor,
         primaryTextColor,
@@ -79,23 +79,24 @@ class OnRamperBuyProvider extends BuyProvider {
     return Uri.https(_baseUrl, '', <String, dynamic>{
       'apiKey': _apiKey,
       'defaultCrypto': _normalizeCryptoCurrency,
+      'sell_defaultCrypto': _normalizeCryptoCurrency,
       'networkWallets': '${networkName}:${wallet.walletAddresses.address}',
-      'supportSell': "false",
       'supportSwap': "false",
       'primaryColor': primaryColor,
       'secondaryColor': secondaryColor,
       'primaryTextColor': primaryTextColor,
       'secondaryTextColor': secondaryTextColor,
       'containerColor': containerColor,
-      'cardColor': cardColor
+      'cardColor': cardColor,
+      'mode': isBuyAction == true ? 'buy' : 'sell',
     });
   }
 
   Future<void> launchProvider(BuildContext context, bool? isBuyAction) async {
-    final uri = requestOnramperUrl(context);
+    final uri = requestOnramperUrl(context, isBuyAction);
     if (DeviceInfo.instance.isMobile) {
       Navigator.of(context)
-          .pushNamed(Routes.webViewPage, arguments: [S.of(context).buy, uri]);
+          .pushNamed(Routes.webViewPage, arguments: [title, uri]);
     } else {
       await launchUrl(uri);
     }
diff --git a/lib/entities/fiat_currency.dart b/lib/entities/fiat_currency.dart
index 8310eb18f..a8e2829d8 100644
--- a/lib/entities/fiat_currency.dart
+++ b/lib/entities/fiat_currency.dart
@@ -10,7 +10,7 @@ class FiatCurrency extends EnumerableItem<String> with Serializable<String> impl
   static List<FiatCurrency> get all => _all.values.toList();
 
   static List<FiatCurrency> get currenciesAvailableToBuyWith =>
-      [aud, bgn, brl, cad, chf, clp, cop, czk, dkk, egp, eur, gbp, gtq, hkd, hrk, huf, idr, ils, inr, isk, jpy, krw, mad, mxn, myr, ngn, nok, nzd, php, pkr, pln, ron, sek, sgd, thb, twd, usd, vnd, zar];
+      [aud, bgn, brl, cad, chf, clp, cop, czk, dkk, egp, eur, gbp, gtq, hkd, hrk, huf, idr, ils, inr, isk, jpy, krw, mad, mxn, myr, ngn, nok, nzd, php, pkr, pln, ron, sek, sgd, thb, twd, usd, vnd, zar, tur];
 
   static const ars = FiatCurrency(symbol: 'ARS', countryCode: "arg", fullName: "Argentine Peso");
   static const aud = FiatCurrency(symbol: 'AUD', countryCode: "aus", fullName: "Australian Dollar");
@@ -60,6 +60,7 @@ class FiatCurrency extends EnumerableItem<String> with Serializable<String> impl
   static const vef = FiatCurrency(symbol: 'VEF', countryCode: "ven", fullName: "Venezuelan Bolivar Bolívar");
   static const vnd = FiatCurrency(symbol: 'VND', countryCode: "vnm", fullName: "Vietnamese Dong đồng");
   static const zar = FiatCurrency(symbol: 'ZAR', countryCode: "saf", fullName: "South African Rand");
+  static const tur = FiatCurrency(symbol: 'TRY', countryCode: "tur", fullName: "Turkish Lira");
 
   static final _all = {
     FiatCurrency.ars.raw: FiatCurrency.ars,
@@ -109,7 +110,8 @@ class FiatCurrency extends EnumerableItem<String> with Serializable<String> impl
     FiatCurrency.usd.raw: FiatCurrency.usd,
     FiatCurrency.vef.raw: FiatCurrency.vef,
     FiatCurrency.vnd.raw: FiatCurrency.vnd,
-    FiatCurrency.zar.raw: FiatCurrency.zar
+    FiatCurrency.zar.raw: FiatCurrency.zar,
+    FiatCurrency.tur.raw: FiatCurrency.tur,
   };
 
   static FiatCurrency deserialize({required String raw}) => _all[raw]!;
diff --git a/lib/entities/provider_types.dart b/lib/entities/provider_types.dart
index 4cb9a934f..ced79eae7 100644
--- a/lib/entities/provider_types.dart
+++ b/lib/entities/provider_types.dart
@@ -78,7 +78,8 @@ class ProvidersHelper {
         return [ProviderType.askEachTime, ProviderType.dfx];
       case WalletType.bitcoin:
       case WalletType.ethereum:
-        return [ProviderType.askEachTime, ProviderType.moonpaySell, ProviderType.dfx];
+        return [ProviderType.askEachTime, ProviderType.onramper,
+          ProviderType.moonpaySell, ProviderType.dfx];
       case WalletType.litecoin:
       case WalletType.bitcoinCash:
         return [ProviderType.askEachTime, ProviderType.moonpaySell];
diff --git a/lib/exchange/provider/changenow_exchange_provider.dart b/lib/exchange/provider/changenow_exchange_provider.dart
index 300741a08..c4a96bc5b 100644
--- a/lib/exchange/provider/changenow_exchange_provider.dart
+++ b/lib/exchange/provider/changenow_exchange_provider.dart
@@ -265,6 +265,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
   }
 
   String _normalizeCurrency(CryptoCurrency currency) {
+    if (currency.title == "USDC" && currency.tag == "POLY") {
+      throw "Only Bridged USDC (USDC.e) is allowed in ChangeNow";
+    }
     switch (currency) {
       case CryptoCurrency.zec:
         return 'zec';
diff --git a/lib/nano/cw_nano.dart b/lib/nano/cw_nano.dart
index 0c072c95c..06ebf60c2 100644
--- a/lib/nano/cw_nano.dart
+++ b/lib/nano/cw_nano.dart
@@ -173,7 +173,7 @@ class CWNano extends Nano {
   }
 
   @override
-  Future<void> updateTransactions(Object wallet) async {
+  Future<bool> updateTransactions(Object wallet) async {
     return (wallet as NanoWallet).updateTransactions();
   }
 
@@ -189,116 +189,10 @@ class CWNano extends Nano {
 }
 
 class CWNanoUtil extends NanoUtil {
-  // standard:
-  @override
-  String seedToPrivate(String seed, int index) {
-    return ND.NanoKeys.seedToPrivate(seed, index);
-  }
-
-  @override
-  String seedToAddress(String seed, int index) {
-    return ND.NanoAccounts.createAccount(
-        ND.NanoAccountType.NANO, privateKeyToPublic(seedToPrivate(seed, index)));
-  }
-
-  @override
-  String seedToMnemonic(String seed) {
-    return NanoMnemomics.seedToMnemonic(seed).join(" ");
-  }
-
-  @override
-  Future<String> mnemonicToSeed(String mnemonic) async {
-    return NanoMnemomics.mnemonicListToSeed(mnemonic.split(' '));
-  }
-
-  @override
-  String privateKeyToPublic(String privateKey) {
-    // return NanoHelpers.byteToHex(Ed25519Blake2b.getPubkey(NanoHelpers.hexToBytes(privateKey))!);
-    return ND.NanoKeys.createPublicKey(privateKey);
-  }
-
-  @override
-  String addressToPublicKey(String publicAddress) {
-    return ND.NanoAccounts.extractPublicKey(publicAddress);
-  }
-
-  // universal:
-  @override
-  String privateKeyToAddress(String privateKey) {
-    return ND.NanoAccounts.createAccount(ND.NanoAccountType.NANO, privateKeyToPublic(privateKey));
-  }
-
-  @override
-  String publicKeyToAddress(String publicKey) {
-    return ND.NanoAccounts.createAccount(ND.NanoAccountType.NANO, publicKey);
-  }
-
-  // standard + hd:
-  @override
-  bool isValidSeed(String seed) {
-    // Ensure seed is 64 or 128 characters long
-    if (seed.length != 64 && seed.length != 128) {
-      return false;
-    }
-    // Ensure seed only contains hex characters, 0-9;A-F
-    return ND.NanoHelpers.isHexString(seed);
-  }
-
-  // hd:
-  @override
-  Future<String> hdMnemonicListToSeed(List<String> words) async {
-    // if (words.length != 24) {
-    //   throw Exception('Expected a 24-word list, got a ${words.length} list');
-    // }
-    final Uint8List salt = Uint8List.fromList(utf8.encode('mnemonic'));
-    final Pbkdf2 hasher = Pbkdf2(iterations: 2048);
-    final String seed = await hasher.sha512(words.join(' '), salt);
-    return seed;
-  }
-
-  @override
-  Future<String> hdSeedToPrivate(String seed, int index) async {
-    List<int> seedBytes = hex.decode(seed);
-    KeyData data = await ED25519_HD_KEY.derivePath("m/44'/165'/$index'", seedBytes);
-    return hex.encode(data.key);
-  }
-
-  @override
-  Future<String> hdSeedToAddress(String seed, int index) async {
-    return ND.NanoAccounts.createAccount(
-        ND.NanoAccountType.NANO, privateKeyToPublic(await hdSeedToPrivate(seed, index)));
-  }
-
-  @override
-  Future<String> uniSeedToAddress(String seed, int index, String type) {
-    if (type == "standard") {
-      return Future<String>.value(seedToAddress(seed, index));
-    } else if (type == "hd") {
-      return hdSeedToAddress(seed, index);
-    } else {
-      throw Exception('Unknown seed type');
-    }
-  }
-
-  @override
-  Future<String> uniSeedToPrivate(String seed, int index, String type) {
-    if (type == "standard") {
-      return Future<String>.value(seedToPrivate(seed, index));
-    } else if (type == "hd") {
-      return hdSeedToPrivate(seed, index);
-    } else {
-      throw Exception('Unknown seed type');
-    }
-  }
 
   @override
   bool isValidBip39Seed(String seed) {
-    // Ensure seed is 128 characters long
-    if (seed.length != 128) {
-      return false;
-    }
-    // Ensure seed only contains hex characters, 0-9;A-F
-    return ND.NanoHelpers.isHexString(seed);
+    return NanoDerivations.isValidBip39Seed(seed);
   }
 
   // number util:
@@ -309,92 +203,20 @@ class CWNanoUtil extends NanoUtil {
   BigInt rawPerBanano = BigInt.parse("100000000000000000000000000000");
   BigInt rawPerXMR = BigInt.parse("1000000000000");
   BigInt convertXMRtoNano = BigInt.parse("1000000000000000000");
-  // static BigInt convertXMRtoNano = BigInt.parse("1000000000000000000000000000");
 
-  /// Convert raw to ban and return as BigDecimal
-  ///
-  /// @param raw 100000000000000000000000000000
-  /// @return Decimal value 1.000000000000000000000000000000
-  ///
-  Decimal _getRawAsDecimal(String? raw, BigInt? rawPerCur) {
-    rawPerCur ??= rawPerNano;
-    final Decimal amount = Decimal.parse(raw.toString());
-    final Decimal result = (amount / Decimal.parse(rawPerCur.toString())).toDecimal();
-    return result;
-  }
-
-  @override
-  String getRawAsDecimalString(String? raw, BigInt? rawPerCur) {
-    final Decimal result = _getRawAsDecimal(raw, rawPerCur);
-    return result.toString();
-  }
-
-  @override
-  String truncateDecimal(Decimal input, {int digits = maxDecimalDigits}) {
-    Decimal bigger = input.shift(digits);
-    bigger = bigger.floor(); // chop off the decimal: 1.059 -> 1.05
-    bigger = bigger.shift(-digits);
-    return bigger.toString();
-  }
-
-  /// Return raw as a NANO amount.
-  ///
-  /// @param raw 100000000000000000000000000000
-  /// @returns 1
-  ///
   @override
   String getRawAsUsableString(String? raw, BigInt rawPerCur) {
-    final String res =
-        truncateDecimal(_getRawAsDecimal(raw, rawPerCur), digits: maxDecimalDigits + 9);
-
-    if (raw == null || raw == "0" || raw == "00000000000000000000000000000000") {
-      return "0";
-    }
-
-    if (!res.contains(".")) {
-      return res;
-    }
-
-    final String numAmount = res.split(".")[0];
-    String decAmount = res.split(".")[1];
-
-    // truncate:
-    if (decAmount.length > maxDecimalDigits) {
-      decAmount = decAmount.substring(0, maxDecimalDigits);
-      // remove trailing zeros:
-      decAmount = decAmount.replaceAllMapped(RegExp(r'0+$'), (Match match) => '');
-      if (decAmount.isEmpty) {
-        return numAmount;
-      }
-    }
-
-    return "$numAmount.$decAmount";
+    return NanoAmounts.getRawAsUsableString(raw, rawPerCur);
   }
 
   @override
   String getRawAccuracy(String? raw, BigInt rawPerCur) {
-    final String rawString = getRawAsUsableString(raw, rawPerCur);
-    final String rawDecimalString = _getRawAsDecimal(raw, rawPerCur).toString();
-
-    if (raw == null || raw.isEmpty || raw == "0") {
-      return "";
-    }
-
-    if (rawString != rawDecimalString) {
-      return "~";
-    }
-    return "";
+    return NanoAmounts.getRawAccuracy(raw, rawPerCur);
   }
 
-  /// Return readable string amount as raw string
-  /// @param amount 1.01
-  /// @returns  101000000000000000000000000000
-  ///
   @override
   String getAmountAsRaw(String amount, BigInt rawPerCur) {
-    final Decimal asDecimal = Decimal.parse(amount);
-    final Decimal rawDecimal = Decimal.parse(rawPerCur.toString());
-    return (asDecimal * rawDecimal).toString();
+    return NanoAmounts.getAmountAsRaw(amount, rawPerCur);
   }
 
   @override
@@ -411,29 +233,29 @@ class CWNanoUtil extends NanoUtil {
     if (seedKey != null) {
       if (seedKey.length == 64) {
         try {
-          mnemonic = nanoUtil!.seedToMnemonic(seedKey);
+          mnemonic = NanoDerivations.standardSeedToMnemonic(seedKey);
         } catch (e) {
           print("not a valid 'nano' seed key");
         }
       }
       if (derivationType == DerivationType.bip39) {
-        publicAddress = await hdSeedToAddress(seedKey, 0);
+        publicAddress = await NanoDerivations.hdSeedToAddress(seedKey, index: 0);
       } else if (derivationType == DerivationType.nano) {
-        publicAddress = await seedToAddress(seedKey, 0);
+        publicAddress = await NanoDerivations.standardSeedToAddress(seedKey, index: 0);
       }
     }
 
     if (derivationType == DerivationType.bip39) {
       if (mnemonic != null) {
-        seedKey = await hdMnemonicListToSeed(mnemonic.split(' '));
-        publicAddress = await hdSeedToAddress(seedKey, 0);
+        seedKey = await NanoDerivations.hdMnemonicListToSeed(mnemonic.split(' '));
+        publicAddress = await NanoDerivations.hdSeedToAddress(seedKey, index: 0);
       }
     }
 
     if (derivationType == DerivationType.nano) {
       if (mnemonic != null) {
-        seedKey = await mnemonicToSeed(mnemonic);
-        publicAddress = await seedToAddress(seedKey, 0);
+        seedKey = await NanoDerivations.standardMnemonicToSeed(mnemonic);
+        publicAddress = await NanoDerivations.standardSeedToAddress(seedKey, index: 0);
       }
     }
 
@@ -461,7 +283,7 @@ class CWNanoUtil extends NanoUtil {
       return [DerivationType.bip39];
     } else if (seedKey?.length == 64) {
       try {
-        mnemonic = nanoUtil!.seedToMnemonic(seedKey!);
+        mnemonic = NanoDerivations.standardSeedToMnemonic(seedKey!);
       } catch (e) {
         print("not a valid 'nano' seed key");
       }
@@ -475,19 +297,19 @@ class CWNanoUtil extends NanoUtil {
       nanoClient.connect(node);
 
       if (mnemonic != null) {
-        seedKey = await hdMnemonicListToSeed(mnemonic.split(' '));
-        publicAddressBip39 = await hdSeedToAddress(seedKey, 0);
+        seedKey = await NanoDerivations.hdMnemonicListToSeed(mnemonic.split(' '));
+        publicAddressBip39 = await NanoDerivations.hdSeedToAddress(seedKey, index: 0);
 
-        seedKey = await mnemonicToSeed(mnemonic);
-        publicAddressStandard = await seedToAddress(seedKey, 0);
+        seedKey = await NanoDerivations.standardMnemonicToSeed(mnemonic);
+        publicAddressStandard = await NanoDerivations.standardSeedToAddress(seedKey, index: 0);
       } else if (seedKey != null) {
         try {
-          publicAddressBip39 = await hdSeedToAddress(seedKey, 0);
+          publicAddressBip39 = await NanoDerivations.hdSeedToAddress(seedKey, index: 0);
         } catch (e) {
           return [DerivationType.nano];
         }
         try {
-          publicAddressStandard = await seedToAddress(seedKey, 0);
+          publicAddressStandard = await NanoDerivations.standardSeedToAddress(seedKey, index: 0);
         } catch (e) {
           return [DerivationType.bip39];
         }
diff --git a/lib/src/screens/buy/buy_webview_page.dart b/lib/src/screens/buy/buy_webview_page.dart
index 6f7a39322..829bff3d9 100644
--- a/lib/src/screens/buy/buy_webview_page.dart
+++ b/lib/src/screens/buy/buy_webview_page.dart
@@ -1,10 +1,7 @@
 import 'dart:async';
-import 'dart:io';
-import 'package:cake_wallet/buy/buy_provider.dart';
 import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
 import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
 import 'package:cake_wallet/generated/i18n.dart';
-import 'package:cake_wallet/palette.dart';
 import 'package:cake_wallet/src/screens/base_page.dart';
 import 'package:cake_wallet/store/dashboard/orders_store.dart';
 import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
@@ -72,10 +69,10 @@ class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
   Widget build(BuildContext context) {
     return InAppWebView(
         key: _webViewkey,
-        initialOptions: InAppWebViewGroupOptions(
-          crossPlatform: InAppWebViewOptions(transparentBackground: true),
+        initialSettings: InAppWebViewSettings(
+          transparentBackground: true,
         ),
-        initialUrlRequest: URLRequest(url: Uri.tryParse(widget.url ?? '')),
+        initialUrlRequest: URLRequest(url: WebUri(widget.url ?? '')),
         onWebViewCreated: (InAppWebViewController controller) =>
             setState(() => _webViewController = controller));
   }
diff --git a/lib/src/screens/buy/webview_page.dart b/lib/src/screens/buy/webview_page.dart
index 205b87c47..97387c29a 100644
--- a/lib/src/screens/buy/webview_page.dart
+++ b/lib/src/screens/buy/webview_page.dart
@@ -1,5 +1,3 @@
-import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
-import 'package:cake_wallet/generated/i18n.dart';
 import 'package:cake_wallet/src/screens/base_page.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_inappwebview/flutter_inappwebview.dart';
@@ -35,21 +33,21 @@ class WebViewPageBodyState extends State<WebViewPageBody> {
   @override
   Widget build(BuildContext context) {
     return InAppWebView(
-      initialOptions: InAppWebViewGroupOptions(
-        crossPlatform: InAppWebViewOptions(transparentBackground: true),
+      initialSettings: InAppWebViewSettings(
+        transparentBackground: true,
       ),
-      initialUrlRequest: URLRequest(url: widget.uri),
-      androidOnPermissionRequest: (_, __, resources) async {
+      initialUrlRequest: URLRequest(url: WebUri.uri(widget.uri)),
+      onPermissionRequest: (controller, request) async {
         bool permissionGranted = await Permission.camera.status == PermissionStatus.granted;
         if (!permissionGranted) {
           permissionGranted = await Permission.camera.request().isGranted;
         }
 
-        return PermissionRequestResponse(
-          resources: resources,
+        return PermissionResponse(
+          resources: request.resources,
           action: permissionGranted
-              ? PermissionRequestResponseAction.GRANT
-              : PermissionRequestResponseAction.DENY,
+              ? PermissionResponseAction.GRANT
+              : PermissionResponseAction.DENY,
         );
       },
     );
diff --git a/lib/src/screens/dashboard/pages/balance_page.dart b/lib/src/screens/dashboard/pages/balance_page.dart
index 283d2171d..6ddd8f6e1 100644
--- a/lib/src/screens/dashboard/pages/balance_page.dart
+++ b/lib/src/screens/dashboard/pages/balance_page.dart
@@ -1,3 +1,5 @@
+import 'dart:math';
+
 import 'package:auto_size_text/auto_size_text.dart';
 import 'package:cake_wallet/generated/i18n.dart';
 import 'package:cake_wallet/reactions/wallet_connect.dart';
@@ -14,6 +16,7 @@ import 'package:cake_wallet/utils/feature_flag.dart';
 import 'package:cake_wallet/utils/show_pop_up.dart';
 import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
 import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
+import 'package:cw_core/crypto_currency.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_mobx/flutter_mobx.dart';
 
@@ -200,7 +203,7 @@ class CryptoBalanceWidget extends StatelessWidget {
                       additionalFiatBalance: balance.fiatAdditionalBalance,
                       frozenBalance: balance.frozenBalance,
                       frozenFiatBalance: balance.fiatFrozenBalance,
-                      currency: balance.formattedAssetTitle,
+                      currency: balance.asset,
                       hasAdditionalBalance:
                           dashboardViewModel.balanceViewModel.hasAdditionalBalance,
                     );
@@ -216,7 +219,7 @@ class CryptoBalanceWidget extends StatelessWidget {
 }
 
 class BalanceRowWidget extends StatelessWidget {
-  const BalanceRowWidget({
+  BalanceRowWidget({
     required this.availableBalanceLabel,
     required this.availableBalance,
     required this.availableFiatBalance,
@@ -238,7 +241,7 @@ class BalanceRowWidget extends StatelessWidget {
   final String additionalFiatBalance;
   final String frozenBalance;
   final String frozenFiatBalance;
-  final String currency;
+  final CryptoCurrency currency;
   final bool hasAdditionalBalance;
 
   // void _showBalanceDescription(BuildContext context) {
@@ -268,7 +271,7 @@ class BalanceRowWidget extends StatelessWidget {
           children: [
             Row(
               mainAxisAlignment: MainAxisAlignment.spaceBetween,
-              crossAxisAlignment: CrossAxisAlignment.start,
+              crossAxisAlignment: CrossAxisAlignment.center,
               children: [
                 GestureDetector(
                   behavior: HitTestBehavior.opaque,
@@ -325,13 +328,48 @@ class BalanceRowWidget extends StatelessWidget {
                     ],
                   ),
                 ),
-                Text(currency,
-                    style: TextStyle(
-                        fontSize: 28,
-                        fontFamily: 'Lato',
-                        fontWeight: FontWeight.w800,
-                        color: Theme.of(context).extension<BalancePageTheme>()!.assetTitleColor,
-                        height: 1)),
+                SizedBox(
+                  width: MediaQuery.of(context).size.width * 0.18,
+                  child: Center(
+                    child: Column(
+                      children: [
+                        currency.iconPath != null
+                            ? Container(
+                                child: Image.asset(
+                                  currency.iconPath!,
+                                  height: 30.0,
+                                  width: 30.0,
+                                ),
+                              )
+                            : Container(
+                                height: 30.0,
+                                width: 30.0,
+                                child: Center(
+                                  child: Text(
+                                    currency.title.substring(0, min(currency.title.length, 2)),
+                                    style: TextStyle(fontSize: 11),
+                                  ),
+                                ),
+                                decoration: BoxDecoration(
+                                  shape: BoxShape.circle,
+                                  color: Colors.grey.shade400,
+                                ),
+                              ),
+                        const SizedBox(height: 10),
+                        Text(
+                          currency.title,
+                          style: TextStyle(
+                            fontSize: 18,
+                            fontFamily: 'Lato',
+                            fontWeight: FontWeight.w800,
+                            color: Theme.of(context).extension<BalancePageTheme>()!.assetTitleColor,
+                            height: 1,
+                          ),
+                        ),
+                      ],
+                    ),
+                  ),
+                ),
               ],
             ),
             if (frozenBalance.isNotEmpty)
@@ -374,7 +412,9 @@ class BalanceRowWidget extends StatelessWidget {
                         fontSize: 20,
                         fontFamily: 'Lato',
                         fontWeight: FontWeight.w400,
-                        color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
+                        color: Theme.of(context)
+                            .extension<BalancePageTheme>()!
+                            .balanceAmountColor,
                         height: 1,
                       ),
                       maxLines: 1,
@@ -388,7 +428,7 @@ class BalanceRowWidget extends StatelessWidget {
                         fontSize: 12,
                         fontFamily: 'Lato',
                         fontWeight: FontWeight.w400,
-                        color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
+                        color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
                         height: 1,
                       ),
                     ),
diff --git a/lib/src/screens/dashboard/pages/transactions_page.dart b/lib/src/screens/dashboard/pages/transactions_page.dart
index 1be8a2a65..c983b1c37 100644
--- a/lib/src/screens/dashboard/pages/transactions_page.dart
+++ b/lib/src/screens/dashboard/pages/transactions_page.dart
@@ -49,7 +49,7 @@ class TransactionsPage extends StatelessWidget {
                     onTap: () => Navigator.of(context).pushNamed(Routes.webViewPage, arguments: [
                       '',
                       Uri.parse(
-                          'https://guides.cakewallet.com/docs/bugs-service-status/why_are_my_funds_not_appearing/')
+                          'https://guides.cakewallet.com/docs/FAQ/why_are_my_funds_not_appearing/')
                     ]),
                     title: S.of(context).syncing_wallet_alert_title,
                     subTitle: S.of(context).syncing_wallet_alert_content,
diff --git a/lib/src/screens/exchange_trade/exchange_trade_page.dart b/lib/src/screens/exchange_trade/exchange_trade_page.dart
index e72b0f0a8..7930c9c82 100644
--- a/lib/src/screens/exchange_trade/exchange_trade_page.dart
+++ b/lib/src/screens/exchange_trade/exchange_trade_page.dart
@@ -261,7 +261,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
                     fee: S.of(popupContext).send_fee,
                     feeValue: widget.exchangeTradeViewModel.sendViewModel
                         .pendingTransaction!.feeFormatted,
-                    rightButtonText: S.of(popupContext).ok,
+                    rightButtonText: S.of(popupContext).send,
                     leftButtonText: S.of(popupContext).cancel,
                     actionRightButton: () async {
                       Navigator.of(popupContext).pop();
diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart
index b20b94cba..3746118d8 100644
--- a/lib/src/screens/send/send_page.dart
+++ b/lib/src/screens/send/send_page.dart
@@ -423,7 +423,7 @@ class SendPage extends BasePage {
                       feeValue: sendViewModel.pendingTransaction!.feeFormatted,
                       feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmountFormatted,
                       outputs: sendViewModel.outputs,
-                      rightButtonText: S.of(_dialogContext).ok,
+                      rightButtonText: S.of(_dialogContext).send,
                       leftButtonText: S.of(_dialogContext).cancel,
                       actionRightButton: () {
                         Navigator.of(_dialogContext).pop();
diff --git a/lib/src/screens/support_chat/widgets/chatwoot_widget.dart b/lib/src/screens/support_chat/widgets/chatwoot_widget.dart
index 73403d667..2557761a7 100644
--- a/lib/src/screens/support_chat/widgets/chatwoot_widget.dart
+++ b/lib/src/screens/support_chat/widgets/chatwoot_widget.dart
@@ -22,17 +22,17 @@ class ChatwootWidgetState extends State<ChatwootWidget> {
   @override
   Widget build(BuildContext context) => InAppWebView(
         key: _webViewkey,
-        initialOptions: InAppWebViewGroupOptions(
-          crossPlatform: InAppWebViewOptions(transparentBackground: true),
-        ),
-        initialUrlRequest: URLRequest(url: Uri.tryParse(widget.supportUrl)),
+    initialSettings: InAppWebViewSettings(
+      transparentBackground: true,
+    ),
+        initialUrlRequest: URLRequest(url: WebUri(widget.supportUrl)),
         onWebViewCreated: (InAppWebViewController controller) {
           controller.addWebMessageListener(
             WebMessageListener(
               jsObjectName: 'ReactNativeWebView',
-              onPostMessage: (String? message, Uri? sourceOrigin, bool isMainFrame,
-                  JavaScriptReplyProxy replyProxy) {
-                final shortenedMessage = message?.substring(16);
+              onPostMessage: (WebMessage? message, WebUri? sourceOrigin, bool isMainFrame,
+                  PlatformJavaScriptReplyProxy replyProxy) {
+                final shortenedMessage = message?.data.toString().substring(16);
                 if (shortenedMessage != null && isJsonString(shortenedMessage)) {
                   final parsedMessage = jsonDecode(shortenedMessage);
                   final eventType = parsedMessage["event"];
diff --git a/lib/view_model/dashboard/balance_view_model.dart b/lib/view_model/dashboard/balance_view_model.dart
index 5c95ab3ab..e2c0382b0 100644
--- a/lib/view_model/dashboard/balance_view_model.dart
+++ b/lib/view_model/dashboard/balance_view_model.dart
@@ -125,6 +125,8 @@ abstract class BalanceViewModelBase with Store {
       case WalletType.haven:
       case WalletType.ethereum:
       case WalletType.polygon:
+      case WalletType.nano:
+      case WalletType.banano:
         return S.current.xmr_available_balance;
       default:
         return S.current.confirmed;
@@ -139,6 +141,9 @@ abstract class BalanceViewModelBase with Store {
       case WalletType.ethereum:
       case WalletType.polygon:
         return S.current.xmr_full_balance;
+      case WalletType.nano:
+      case WalletType.banano:
+        return S.current.receivable_balance;
       default:
         return S.current.unconfirmed;
     }
diff --git a/lib/view_model/dashboard/transaction_list_item.dart b/lib/view_model/dashboard/transaction_list_item.dart
index bc7f70517..d8c4776b7 100644
--- a/lib/view_model/dashboard/transaction_list_item.dart
+++ b/lib/view_model/dashboard/transaction_list_item.dart
@@ -101,7 +101,7 @@ class TransactionListItem extends ActionListItem with Keyable {
         break;
       case WalletType.nano:
         amount = calculateFiatAmountRaw(
-            cryptoAmount: double.parse(nanoUtil!.getRawAsDecimalString(
+            cryptoAmount: double.parse(nanoUtil!.getRawAsUsableString(
                 nano!.getTransactionAmountRaw(transaction).toString(), nanoUtil!.rawPerNano)),
             price: price);
         break;
diff --git a/lib/view_model/transaction_details_view_model.dart b/lib/view_model/transaction_details_view_model.dart
index 4e17866cb..f9ff466a7 100644
--- a/lib/view_model/transaction_details_view_model.dart
+++ b/lib/view_model/transaction_details_view_model.dart
@@ -247,11 +247,15 @@ abstract class TransactionDetailsViewModelBase with Store {
   void _addNanoListItems(TransactionInfo tx, DateFormat dateFormat) {
     final _items = [
       StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
+      if (showRecipientAddress && tx.to != null)
+        StandartListItem(title: S.current.transaction_details_recipient_address, value: tx.to!),
+      if (showRecipientAddress && tx.from != null)
+        StandartListItem(title: S.current.transaction_details_source_address, value: tx.from!),
+      StandartListItem(title: S.current.transaction_details_amount, value: tx.amountFormatted()),
       StandartListItem(
           title: S.current.transaction_details_date, value: dateFormat.format(tx.date)),
-      StandartListItem(title: S.current.confirmations, value: (tx.confirmations > 0).toString()),
+      StandartListItem(title: S.current.confirmed_tx, value: (tx.confirmations > 0).toString()),
       StandartListItem(title: S.current.transaction_details_height, value: '${tx.height}'),
-      StandartListItem(title: S.current.transaction_details_amount, value: tx.amountFormatted()),
     ];
 
     items.addAll(_items);
diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift
index 68d03b5f8..05996a674 100644
--- a/macos/Flutter/GeneratedPluginRegistrant.swift
+++ b/macos/Flutter/GeneratedPluginRegistrant.swift
@@ -9,6 +9,7 @@ import connectivity_plus_macos
 import cw_monero
 import device_info_plus
 import devicelocale
+import flutter_inappwebview_macos
 import flutter_secure_storage_macos
 import in_app_review
 import package_info
@@ -24,6 +25,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
   CwMoneroPlugin.register(with: registry.registrar(forPlugin: "CwMoneroPlugin"))
   DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
   DevicelocalePlugin.register(with: registry.registrar(forPlugin: "DevicelocalePlugin"))
+  InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
   FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
   InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin"))
   FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin"))
diff --git a/pubspec_base.yaml b/pubspec_base.yaml
index e326e8ea1..63a97b7d2 100644
--- a/pubspec_base.yaml
+++ b/pubspec_base.yaml
@@ -43,7 +43,7 @@ dependencies:
   auto_size_text: ^3.0.0
   dotted_border: ^2.0.0+2
   smooth_page_indicator: ^1.0.0+2
-  flutter_inappwebview: ^5.7.2+3
+  flutter_inappwebview: ^6.0.0
   flutter_spinkit: ^5.1.0
   uni_links: ^0.5.1
   lottie: ^1.3.0
diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb
index e10f136e4..8fcccd967 100644
--- a/res/values/strings_ar.arb
+++ b/res/values/strings_ar.arb
@@ -765,5 +765,8 @@
   "connected": "متصل",
   "disconnected": "انقطع الاتصال",
   "onion_only": "البصل فقط",
-  "connecting": "توصيل"
+  "connecting": "توصيل",
+  "receivable_balance": "التوازن القادم",
+  "confirmed_tx": "مؤكد",
+  "transaction_details_source_address": "عنوان المصدر"
 }
\ No newline at end of file
diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb
index 62480c1da..f859d839f 100644
--- a/res/values/strings_bg.arb
+++ b/res/values/strings_bg.arb
@@ -761,5 +761,8 @@
   "connected": "Свързани",
   "disconnected": "Изключен",
   "onion_only": "Само лук",
-  "connecting": "Свързване"
+  "connecting": "Свързване",
+  "receivable_balance": "Баланс за вземания",
+  "confirmed_tx": "Потвърдено",
+  "transaction_details_source_address": "Адрес на източника"
 }
\ No newline at end of file
diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb
index af2722c01..061e4d9bf 100644
--- a/res/values/strings_cs.arb
+++ b/res/values/strings_cs.arb
@@ -761,5 +761,8 @@
   "connected": "Připojeno",
   "disconnected": "Odpojené",
   "onion_only": "Pouze cibule",
-  "connecting": "Spojovací"
+  "connecting": "Spojovací",
+  "receivable_balance": "Zůstatek pohledávek",
+  "confirmed_tx": "Potvrzeno",
+  "transaction_details_source_address": "Zdrojová adresa"
 }
\ No newline at end of file
diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb
index 8d83c101a..a16c0c492 100644
--- a/res/values/strings_de.arb
+++ b/res/values/strings_de.arb
@@ -769,5 +769,8 @@
   "connected": "In Verbindung gebracht",
   "disconnected": "Getrennt",
   "onion_only": "Nur Zwiebel",
-  "connecting": "Verbinden"
+  "connecting": "Verbinden",
+  "receivable_balance": "Forderungsbilanz",
+  "confirmed_tx": "Bestätigt",
+  "transaction_details_source_address": "Quelladresse"
 }
\ No newline at end of file
diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb
index e0ab03a75..2f73d5fbf 100644
--- a/res/values/strings_en.arb
+++ b/res/values/strings_en.arb
@@ -770,5 +770,8 @@
   "connected": "Connected",
   "disconnected": "Disconnected",
   "onion_only": "Onion only",
-  "connecting": "Connecting"
+  "connecting": "Connecting",
+  "receivable_balance": "Receivable Balance",
+  "confirmed_tx": "Confirmed",
+  "transaction_details_source_address": "Source address"
 }
\ No newline at end of file
diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb
index 3dfe21be6..02de41f99 100644
--- a/res/values/strings_es.arb
+++ b/res/values/strings_es.arb
@@ -769,5 +769,8 @@
   "connected": "Conectado",
   "disconnected": "Desconectado",
   "onion_only": "Solo cebolla",
-  "connecting": "Conexión"
+  "connecting": "Conexión",
+  "receivable_balance": "Saldo de cuentas por cobrar",
+  "confirmed_tx": "Confirmado",
+  "transaction_details_source_address": "Dirección de la fuente"
 }
\ No newline at end of file
diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb
index 73810551f..5a54669fe 100644
--- a/res/values/strings_fr.arb
+++ b/res/values/strings_fr.arb
@@ -769,5 +769,8 @@
   "connected": "Connecté",
   "disconnected": "Débranché",
   "onion_only": "Oignon seulement",
-  "connecting": "De liaison"
+  "connecting": "De liaison",
+  "receivable_balance": "Solde de créances",
+  "confirmed_tx": "Confirmé",
+  "transaction_details_source_address": "Adresse source"
 }
\ No newline at end of file
diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb
index 36662695c..bbb1e3e67 100644
--- a/res/values/strings_ha.arb
+++ b/res/values/strings_ha.arb
@@ -751,5 +751,8 @@
   "connected": "Wanda aka haɗa",
   "disconnected": "Katse",
   "onion_only": "Albasa kawai",
-  "connecting": "Haɗa"
+  "connecting": "Haɗa",
+  "receivable_balance": "Daidaituwa da daidaituwa",
+  "confirmed_tx": "Tabbatar",
+  "transaction_details_source_address": "Adireshin Incord"
 }
\ No newline at end of file
diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb
index 94a7ec371..ec2f9d197 100644
--- a/res/values/strings_hi.arb
+++ b/res/values/strings_hi.arb
@@ -769,5 +769,8 @@
   "connected": "जुड़े हुए",
   "disconnected": "डिस्कनेक्ट किया गया",
   "onion_only": "केवल प्याज",
-  "connecting": "कनेक्ट"
+  "connecting": "कनेक्ट",
+  "receivable_balance": "प्राप्य शेष",
+  "confirmed_tx": "की पुष्टि",
+  "transaction_details_source_address": "स्रोत पता"
 }
\ No newline at end of file
diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb
index 9f5cae922..87e602257 100644
--- a/res/values/strings_hr.arb
+++ b/res/values/strings_hr.arb
@@ -767,5 +767,8 @@
   "connected": "Povezan",
   "disconnected": "Isključen",
   "onion_only": "Samo luk",
-  "connecting": "Spoj"
+  "connecting": "Spoj",
+  "receivable_balance": "Stanje potraživanja",
+  "confirmed_tx": "Potvrđen",
+  "transaction_details_source_address": "Adresa izvora"
 }
\ No newline at end of file
diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb
index d7c401fbd..e80265c0b 100644
--- a/res/values/strings_id.arb
+++ b/res/values/strings_id.arb
@@ -757,5 +757,8 @@
   "connected": "Terhubung",
   "disconnected": "Terputus",
   "onion_only": "Bawang saja",
-  "connecting": "Menghubungkan"
+  "connecting": "Menghubungkan",
+  "receivable_balance": "Saldo piutang",
+  "confirmed_tx": "Dikonfirmasi",
+  "transaction_details_source_address": "Alamat sumber"
 }
\ No newline at end of file
diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb
index 1421ce901..8ff479392 100644
--- a/res/values/strings_it.arb
+++ b/res/values/strings_it.arb
@@ -769,5 +769,8 @@
   "connected": "Collegato",
   "disconnected": "Disconnesso",
   "onion_only": "Solo cipolla",
-  "connecting": "Connessione"
+  "connecting": "Connessione",
+  "receivable_balance": "Bilanciamento creditizio",
+  "confirmed_tx": "Confermato",
+  "transaction_details_source_address": "Indirizzo di partenza"
 }
\ No newline at end of file
diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb
index d09046388..befaea9b1 100644
--- a/res/values/strings_ja.arb
+++ b/res/values/strings_ja.arb
@@ -769,5 +769,8 @@
   "connected": "接続",
   "disconnected": "切断された",
   "onion_only": "オニオンのみ",
-  "connecting": "接続"
+  "connecting": "接続",
+  "receivable_balance": "売掛金残高",
+  "confirmed_tx": "確認済み",
+  "transaction_details_source_address": "ソースアドレス"
 }
\ No newline at end of file
diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb
index 7a144059e..3fbce31da 100644
--- a/res/values/strings_ko.arb
+++ b/res/values/strings_ko.arb
@@ -767,5 +767,8 @@
   "connected": "연결",
   "disconnected": "연결이 끊어졌습니다",
   "onion_only": "양파 만",
-  "connecting": "연결"
+  "connecting": "연결",
+  "receivable_balance": "채권 잔액",
+  "confirmed_tx": "확인",
+  "transaction_details_source_address": "소스 주소"
 }
\ No newline at end of file
diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb
index 1a8e941ca..f3eb26383 100644
--- a/res/values/strings_my.arb
+++ b/res/values/strings_my.arb
@@ -767,5 +767,8 @@
   "connected": "ချိတ်ဆက်ထားသော",
   "disconnected": "ချို့ယွင်းချက်",
   "onion_only": "သာကြက်သွန်",
-  "connecting": "ချိတ်ဆက်"
+  "connecting": "ချိတ်ဆက်",
+  "receivable_balance": "လက်ကျန်ငွေ",
+  "confirmed_tx": "အတည်ပြုသည်",
+  "transaction_details_source_address": "အရင်းအမြစ်လိပ်စာ"
 }
\ No newline at end of file
diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb
index ade120a6d..fdb64f29c 100644
--- a/res/values/strings_nl.arb
+++ b/res/values/strings_nl.arb
@@ -769,5 +769,8 @@
   "connected": "Verbonden",
   "disconnected": "Losgekoppeld",
   "onion_only": "Alleen ui",
-  "connecting": "Verbinden"
+  "connecting": "Verbinden",
+  "receivable_balance": "Het saldo",
+  "confirmed_tx": "Bevestigd",
+  "transaction_details_source_address": "Bron adres"
 }
\ No newline at end of file
diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb
index b4b18e601..7ae4245a2 100644
--- a/res/values/strings_pl.arb
+++ b/res/values/strings_pl.arb
@@ -769,5 +769,8 @@
   "connected": "Połączony",
   "disconnected": "Bezładny",
   "onion_only": "Tylko cebula",
-  "connecting": "Złączony"
+  "connecting": "Złączony",
+  "receivable_balance": "Saldo należności",
+  "confirmed_tx": "Potwierdzony",
+  "transaction_details_source_address": "Adres źródłowy"
 }
\ No newline at end of file
diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb
index 23aa08742..47bce63ed 100644
--- a/res/values/strings_pt.arb
+++ b/res/values/strings_pt.arb
@@ -768,5 +768,8 @@
   "connected": "Conectado",
   "disconnected": "Desconectado",
   "onion_only": "Apenas cebola",
-  "connecting": "Conectando"
+  "connecting": "Conectando",
+  "receivable_balance": "Saldo a receber",
+  "confirmed_tx": "Confirmado",
+  "transaction_details_source_address": "Endereço de Origem"
 }
\ No newline at end of file
diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb
index d7a54f8d2..5e545eb66 100644
--- a/res/values/strings_ru.arb
+++ b/res/values/strings_ru.arb
@@ -769,5 +769,8 @@
   "connected": "Связанный",
   "disconnected": "Отключен",
   "onion_only": "Только лук",
-  "connecting": "Соединение"
+  "connecting": "Соединение",
+  "receivable_balance": "Баланс дебиторской задолженности",
+  "confirmed_tx": "Подтвержденный",
+  "transaction_details_source_address": "Адрес источника"
 }
\ No newline at end of file
diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb
index 250010649..33facbf80 100644
--- a/res/values/strings_th.arb
+++ b/res/values/strings_th.arb
@@ -767,5 +767,8 @@
   "connected": "ซึ่งเชื่อมต่อกัน",
   "disconnected": "ตัดการเชื่อมต่อ",
   "onion_only": "หัวหอมเท่านั้น",
-  "connecting": "การเชื่อมต่อ"
+  "connecting": "การเชื่อมต่อ",
+  "receivable_balance": "ยอดลูกหนี้",
+  "confirmed_tx": "ซึ่งยืนยันแล้ว",
+  "transaction_details_source_address": "ที่อยู่แหล่งกำเนิด"
 }
\ No newline at end of file
diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb
index 4ae759387..c996aca71 100644
--- a/res/values/strings_tl.arb
+++ b/res/values/strings_tl.arb
@@ -763,5 +763,8 @@
   "connected": "Konektado",
   "disconnected": "Naka -disconnect",
   "onion_only": "Onion lamang",
-  "connecting": "Pagkonekta"
+  "connecting": "Pagkonekta",
+  "receivable_balance": "Natatanggap na balanse",
+  "confirmed_tx": "Nakumpirma",
+  "transaction_details_source_address": "SOURCE ADDRESS"
 }
\ No newline at end of file
diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb
index 19e990b97..0b86b9c6d 100644
--- a/res/values/strings_tr.arb
+++ b/res/values/strings_tr.arb
@@ -767,5 +767,8 @@
   "connected": "Bağlı",
   "disconnected": "Bağlantı kesildi",
   "onion_only": "Sadece soğan",
-  "connecting": "Bağlanıyor"
+  "connecting": "Bağlanıyor",
+  "receivable_balance": "Alacak bakiyesi",
+  "confirmed_tx": "Onaylanmış",
+  "transaction_details_source_address": "Kaynak adresi"
 }
\ No newline at end of file
diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb
index 1da3b4435..63ee5c142 100644
--- a/res/values/strings_uk.arb
+++ b/res/values/strings_uk.arb
@@ -769,5 +769,8 @@
   "connected": "З'єднаний",
   "disconnected": "Роз'єднаний",
   "onion_only": "Тільки цибуля",
-  "connecting": "З'єднання"
+  "connecting": "З'єднання",
+  "receivable_balance": "Баланс дебіторської заборгованості",
+  "confirmed_tx": "Підтверджений",
+  "transaction_details_source_address": "Адреса джерела"
 }
\ No newline at end of file
diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb
index 69abf78e1..e75cb21ba 100644
--- a/res/values/strings_ur.arb
+++ b/res/values/strings_ur.arb
@@ -761,5 +761,8 @@
   "connected": "منسلک",
   "disconnected": "منقطع",
   "onion_only": "صرف پیاز",
-  "connecting": "رابطہ قائم کرنا"
+  "connecting": "رابطہ قائم کرنا",
+  "receivable_balance": "قابل وصول توازن",
+  "confirmed_tx": "تصدیق",
+  "transaction_details_source_address": "ماخذ ایڈریس"
 }
\ No newline at end of file
diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb
index b88126fe8..b7023de7c 100644
--- a/res/values/strings_yo.arb
+++ b/res/values/strings_yo.arb
@@ -763,5 +763,8 @@
   "connected": "Sopọ",
   "disconnected": "Ge asopọ",
   "onion_only": "Alubosa nikan",
-  "connecting": "Asopọ"
+  "connecting": "Asopọ",
+  "receivable_balance": "Iwontunws.funfun ti o gba",
+  "confirmed_tx": "Jẹrisi",
+  "transaction_details_source_address": "Adirẹsi orisun"
 }
\ No newline at end of file
diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb
index 7f43520c4..b67e9c7ff 100644
--- a/res/values/strings_zh.arb
+++ b/res/values/strings_zh.arb
@@ -768,5 +768,8 @@
   "connected": "连接的",
   "disconnected": "断开连接",
   "onion_only": "仅洋葱",
-  "connecting": "连接"
+  "connecting": "连接",
+  "receivable_balance": "应收余额",
+  "confirmed_tx": "确认的",
+  "transaction_details_source_address": "源地址"
 }
\ No newline at end of file
diff --git a/tool/configure.dart b/tool/configure.dart
index 67732faa9..3d1bccb12 100644
--- a/tool/configure.dart
+++ b/tool/configure.dart
@@ -759,7 +759,7 @@ import 'package:convert/convert.dart';
 import "package:ed25519_hd_key/ed25519_hd_key.dart";
 import 'package:libcrypto/libcrypto.dart';
 import 'package:nanodart/nanodart.dart' as ND;
-import 'package:decimal/decimal.dart';
+import 'package:nanoutil/nanoutil.dart';
 """;
   const nanoCwPart = "part 'cw_nano.dart';";
   const nanoContent = """
@@ -795,7 +795,7 @@ abstract class Nano {
   Map<String, String> getKeys(Object wallet);
   Object createNanoTransactionCredentials(List<Output> outputs);
   Future<void> changeRep(Object wallet, String address);
-  Future<void> updateTransactions(Object wallet);
+  Future<bool> updateTransactions(Object wallet);
   BigInt getTransactionAmountRaw(TransactionInfo transactionInfo);
   String getRepresentative(Object wallet);
 }
@@ -810,20 +810,6 @@ abstract class NanoAccountList {
 }
 
 abstract class NanoUtil {
-  String seedToPrivate(String seed, int index);
-  String seedToAddress(String seed, int index);
-  String seedToMnemonic(String seed);
-  Future<String> mnemonicToSeed(String mnemonic);
-  String privateKeyToPublic(String privateKey);
-  String addressToPublicKey(String publicAddress);
-  String privateKeyToAddress(String privateKey);
-  String publicKeyToAddress(String publicKey);
-  bool isValidSeed(String seed);
-  Future<String> hdMnemonicListToSeed(List<String> words);
-  Future<String> hdSeedToPrivate(String seed, int index);
-  Future<String> hdSeedToAddress(String seed, int index);
-  Future<String> uniSeedToAddress(String seed, int index, String type);
-  Future<String> uniSeedToPrivate(String seed, int index, String type);
   bool isValidBip39Seed(String seed);
   static const int maxDecimalDigits = 6; // Max digits after decimal
   BigInt rawPerNano = BigInt.parse("1000000000000000000000000000000");
@@ -831,7 +817,6 @@ abstract class NanoUtil {
   BigInt rawPerBanano = BigInt.parse("100000000000000000000000000000");
   BigInt rawPerXMR = BigInt.parse("1000000000000");
   BigInt convertXMRtoNano = BigInt.parse("1000000000000000000");
-  String getRawAsDecimalString(String? raw, BigInt? rawPerCur);
   String getRawAsUsableString(String? raw, BigInt rawPerCur);
   String getRawAccuracy(String? raw, BigInt rawPerCur);
   String getAmountAsRaw(String amount, BigInt rawPerCur);