Repository: opentensor/btwallet (language: python)

Issue:
Updated readme docs



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ac4913b..295aebd 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,72 +1,155 @@
-name: Build and Publish Python bittensor-wallet
+# This file is autogenerated by maturin v1.7.4
+# To update, run
+#
+#    maturin generate-ci github
+#
+name: Build wheels
 
 on:
+  push:
+    branches:
+      - main
+    tags:
+      - '*'
+  pull_request:
   workflow_dispatch:
-    inputs:
-      version:
-        description: 'Version to release'
-        required: true
-        type: string
+
+permissions:
+  contents: read
 
 jobs:
-  build:
-    name: Build Python distribution
-    runs-on: ubuntu-latest
+  linux:
+    runs-on: ${{ matrix.platform.runner }}
+    strategy:
+      matrix:
+        platform:
+          - runner: ubuntu-latest
+            target: x86_64
+          - runner: ubuntu-latest
+            target: x86
+          # - runner: ubuntu-latest
+          #   target: aarch64
+          # - runner: ubuntu-latest
+          #   target: armv7
+          # - runner: ubuntu-latest
+          #   target: s390x
+          # - runner: ubuntu-latest
+          #   target: ppc64le
     steps:
-    - uses: actions/checkout@v3
-    
-    - name: Set up Python
-      uses: actions/setup-python@v4
-      with:
-        python-version: '3.10'
+      - uses: actions/checkout@v4
+      - uses: actions/setup-python@v5
+        with:
+          python-version: 3.x
+      - name: Build wheels
+        uses: PyO3/maturin-action@v1.44.0
+        with:
+          target: ${{ matrix.platform.target }}
+          args: --release --out dist --find-interpreter
+          sccache: 'true'
+          manylinux: auto
+          before-script-linux: (apt-get update && apt-get install -y apt-utils && apt-get install -y pkg-config libssl-dev) || (yum install openssl openssl-devel -y) 
+      - name: Upload wheels
+        uses: actions/upload-artifact@v4
+        with:
+          name: wheels-linux-${{ matrix.platform.target }}
+          path: dist
 
-    - name: Install dependencies
-      run: |
-        python -m pip install --upgrade pip
-        pip install build wheel twine
+  # musllinux:
+  #   runs-on: ${{ matrix.platform.runner }}
+  #   strategy:
+  #     matrix:
+  #       platform:
+  #         - runner: ubuntu-latest
+  #           target: x86_64
+  #         # - runner: ubuntu-latest
+  #         #   target: x86
+  #         # - runner: ubuntu-latest
+  #         #   target: aarch64
+  #         # - runner: ubuntu-latest
+  #         #   target: armv7
+  #   steps:
+  #     - uses: actions/checkout@v4
+  #     - uses: actions/setup-python@v5
+  #       with:
+  #         python-version: 3.x
+  #     - name: Build wheels
+  #       uses: PyO3/maturin-action@v1.44.0
+  #       with:
+  #         target: ${{ matrix.platform.target }}
+  #         args: --release --out dist --find-interpreter
+  #         sccache: 'true'
+  #         manylinux: musllinux_1_2
+  #         before-script-linux: (apt-get update && apt-get install -y apt-utils && apt-get install -y pkg-config libssl-dev) || (yum install openssl openssl-devel -y) 
+  #     - name: Upload wheels
+  #       uses: actions/upload-artifact@v4
+  #       with:
+  #         name: wheels-musllinux-${{ matrix.platform.target }}
+  #         path: dist
 
-    - name: Build package
-      run: python setup.py sdist bdist_wheel
-
-    - name: Check if package version already exists
-      run: |
-        PACKAGE_NAME=$(python setup.py --name)
-        PACKAGE_VERSION=${{ github.event.inputs.version }}
-        if twine check dist/*; then
-          if pip install $PACKAGE_NAME==$PACKAGE_VERSION; then
-            echo "Error: Version $PACKAGE_VERSION of $PACKAGE_NAME already exists on PyPI"
-            exit 1
-          else
-            echo "Version $PACKAGE_VERSION of $PACKAGE_NAME does not exist on PyPI. Proceeding with upload."
-          fi
-        else
-          echo "Error: Twine check failed."
-          exit 1
-        fi
+  macos:
+    runs-on: ${{ matrix.platform.runner }}
+    strategy:
+      matrix:
+        platform:
+          - runner: macos-12
+            target: x86_64
+          - runner: macos-14
+            target: aarch64
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-python@v5
+        with:
+          python-version: 3.x
+      - name: Build wheels
+        uses: PyO3/maturin-action@v1.44.0
+        with:
+          target: ${{ matrix.platform.target }}
+          args: --release --out dist --find-interpreter
+          sccache: 'true'
+      - name: Upload wheels
+        uses: actions/upload-artifact@v4
+        with:
+          name: wheels-macos-${{ matrix.platform.target }}
+          path: dist
 
-    - name: Upload artifact
-      uses: actions/upload-artifact@v3
-      with:
-        name: dist
-        path: dist/
+  sdist:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - name: Build sdist
+        uses: PyO3/maturin-action@v1.44.0
+        with:
+          command: sdist
+          args: --out dist
+      - name: Upload sdist
+        uses: actions/upload-artifact@v4
+        with:
+          name: wheels-sdist
+          path: dist
 
-  approve-and-publish:
-    needs: build
+  release:
+    name: Release
     runs-on: ubuntu-latest
     environment: release
+    if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }}
+    #needs: [linux, macos, musllinux, sdist]
+    needs: [linux, macos, sdist]
     permissions:
-      contents: read
+      # Use to sign the release artifacts
       id-token: write
-
+      # Used to upload release artifacts
+      contents: write
+      # Used to generate artifact attestation
+      attestations: write
     steps:
-    - name: Download artifact
-      uses: actions/download-artifact@v3
-      with:
-        name: dist
-        path: dist/
-
-    - name: Publish package distributions to PyPI
-      uses: pypa/gh-action-pypi-publish@release/v1
-      with:
-        verbose: true
-        print-hash: true
\ No newline at end of file
+      - uses: actions/download-artifact@v4
+      - name: Generate artifact attestation
+        uses: actions/attest-build-provenance@v1
+        with:
+          subject-path: 'wheels-*/*'
+      - name: Publish to PyPI
+        if: "startsWith(github.ref, 'refs/tags/')"
+        uses: PyO3/maturin-action@v1.44.0
+        with:
+          command: upload
+          args: --non-interactive --skip-existing wheels-*/*
diff --git a/.gitignore b/.gitignore
index 5cc3b79..4496eb4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -213,4 +213,6 @@ replicate.yaml
 # Notebooks
 *.ipynb
 
-tests/zombienet/bin/**/*
\ No newline at end of file
+tests/zombienet/bin/**/*
+
+Cargo.lock
\ No newline at end of file
diff --git a/CHANGELOG.MD b/CHANGELOG.MD
index 8f815c1..34b3a7e 100644
--- a/CHANGELOG.MD
+++ b/CHANGELOG.MD
@@ -1,5 +1,39 @@
 # Changelog
 
+## 2.0.0 /2024-10-03
+
+## What's Changed
+* Massive wallet change after copy-paste by @roman-opentensor in https://github.com/opentensor/btwallet/pull/1
+* Bump substrate-interface to 1.7.9 by @thewhaleking in https://github.com/opentensor/btwallet/pull/3
+* Fix flaky tests by @roman-opentensor in https://github.com/opentensor/btwallet/pull/5
+* Initial commit: circleci testing config by @ibraheem-opentensor in https://github.com/opentensor/btwallet/pull/6
+* bug/roman/requirements by @roman-opentensor in https://github.com/opentensor/btwallet/pull/8
+* License fix by @roman-opentensor in https://github.com/opentensor/btwallet/pull/9
+* Add unlock method for wallet coldkey by @thewhaleking in https://github.com/opentensor/btwallet/pull/10
+* Add `unlock_hotkey` method to the wallet. Add unit tests. by @roman-opentensor in https://github.com/opentensor/btwallet/pull/11
+* Add `unlock_hotkeypub` method to the wallet. Add unit tests. by @roman-opentensor in https://github.com/opentensor/btwallet/pull/12
+* Updates mnemonic command output by @ibraheem-opentensor in https://github.com/opentensor/btwallet/pull/17
+* Raises a KeyFileError when one is encountered when unlocking. by @thewhaleking in https://github.com/opentensor/btwallet/pull/19
+* bump up the version by @roman-opentensor in https://github.com/opentensor/btwallet/pull/20
+* Password unlocking changes  by @thewhaleking in https://github.com/opentensor/btwallet/pull/18
+* bump up cryptography version until 43.0.1 by @roman-opentensor in https://github.com/opentensor/btwallet/pull/21
+* Deployment script + updates by @ibraheem-opentensor in https://github.com/opentensor/btwallet/pull/23
+* Release 1.0.0 - Changelog by @ibraheem-opentensor in https://github.com/opentensor/btwallet/pull/24
+* Pins py-bip39-bindings by @ibraheem-opentensor in https://github.com/opentensor/btwallet/pull/25
+* use pythons stdout by @camfairchild in https://github.com/opentensor/btwallet/pull/30
+* Cam/no excepts by @camfairchild in https://github.com/opentensor/btwallet/pull/32
+* Updated readme docs by @rajkaramchedu in https://github.com/opentensor/btwallet/pull/31
+* Feat/ci/add release by @camfairchild in https://github.com/opentensor/btwallet/pull/38
+
+## New Contributors
+* @roman-opentensor made their first contribution in https://github.com/opentensor/btwallet/pull/1
+* @thewhaleking made their first contribution in https://github.com/opentensor/btwallet/pull/3
+* @ibraheem-opentensor made their first contribution in https://github.com/opentensor/btwallet/pull/6
+* @camfairchild made their first contribution in https://github.com/opentensor/btwallet/pull/30
+* @rajkaramchedu made their first contribution in https://github.com/opentensor/btwallet/pull/31
+
+**Full Changelog**: https://github.com/opentensor/btwallet/commits/v2.0.0
+
 ## 1.0.0 /2024-09-25
 
 ## What's Changed
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..e9dcfcc
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,3059 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "Inflector"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
+dependencies = [
+ "lazy_static",
+ "regex",
+]
+
+[[package]]
+name = "aead"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
+dependencies = [
+ "crypto-common",
+ "generic-array",
+]
+
+[[package]]
+name = "aes-ctr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7729c3cde54d67063be556aeac75a81330d802f0259500ca40cb52967f975763"
+dependencies = [
+ "aes-soft",
+ "aesni",
+ "cipher 0.2.5",
+ "ctr",
+]
+
+[[package]]
+name = "aes-soft"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072"
+dependencies = [
+ "cipher 0.2.5",
+ "opaque-debug",
+]
+
+[[package]]
+name = "aesni"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce"
+dependencies = [
+ "cipher 0.2.5",
+ "opaque-debug",
+]
+
+[[package]]
+name = "ahash"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
+
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "ansible-vault"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee8e42972d7396345d7695c54bc6d4cc1054f21729627d503ff091c962dd51f0"
+dependencies = [
+ "aes-ctr",
+ "block-padding",
+ "hex",
+ "hmac 0.10.1",
+ "pbkdf2 0.7.5",
+ "rand",
+ "sha2 0.9.9",
+]
+
+[[package]]
+name = "ark-bls12-377"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb00293ba84f51ce3bd026bd0de55899c4e68f0a39a5728cebae3a73ffdc0a4f"
+dependencies = [
+ "ark-ec",
+ "ark-ff",
+ "ark-std",
+]
+
+[[package]]
+name = "ark-bls12-381"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488"
+dependencies = [
+ "ark-ec",
+ "ark-ff",
+ "ark-serialize",
+ "ark-std",
+]
+
+[[package]]
+name = "ark-ec"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba"
+dependencies = [
+ "ark-ff",
+ "ark-poly",
+ "ark-serialize",
+ "ark-std",
+ "derivative",
+ "hashbrown 0.13.2",
+ "itertools 0.10.5",
+ "num-traits",
+ "zeroize",
+]
+
+[[package]]
+name = "ark-ff"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba"
+dependencies = [
+ "ark-ff-asm",
+ "ark-ff-macros",
+ "ark-serialize",
+ "ark-std",
+ "derivative",
+ "digest 0.10.7",
+ "itertools 0.10.5",
+ "num-bigint",
+ "num-traits",
+ "paste",
+ "rustc_version",
+ "zeroize",
+]
+
+[[package]]
+name = "ark-ff-asm"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348"
+dependencies = [
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-ff-macros"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565"
+dependencies = [
+ "num-bigint",
+ "num-traits",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-poly"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf"
+dependencies = [
+ "ark-ff",
+ "ark-serialize",
+ "ark-std",
+ "derivative",
+ "hashbrown 0.13.2",
+]
+
+[[package]]
+name = "ark-serialize"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5"
+dependencies = [
+ "ark-serialize-derive",
+ "ark-std",
+ "digest 0.10.7",
+ "num-bigint",
+]
+
+[[package]]
+name = "ark-serialize-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-std"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185"
+dependencies = [
+ "num-traits",
+ "rand",
+]
+
+[[package]]
+name = "array-bytes"
+version = "6.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d5dde061bd34119e902bbb2d9b90c5692635cf59fb91d582c2b68043f1b8293"
+
+[[package]]
+name = "arrayref"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
+
+[[package]]
+name = "autocfg"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+
+[[package]]
+name = "base16ct"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
+
+[[package]]
+name = "base64"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
+
+[[package]]
+name = "base64"
+version = "0.21.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "base64ct"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
+
+[[package]]
+name = "bip39"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f"
+dependencies = [
+ "bitcoin_hashes 0.11.0",
+ "rand",
+ "rand_core",
+ "serde",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "bitcoin-internals"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb"
+
+[[package]]
+name = "bitcoin_hashes"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4"
+
+[[package]]
+name = "bitcoin_hashes"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b"
+dependencies = [
+ "bitcoin-internals",
+ "hex-conservative",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
+[[package]]
+name = "bittensor_wallet"
+version = "2.0.0"
+dependencies = [
+ "ansible-vault",
+ "base64 0.22.1",
+ "bip39",
+ "colored",
+ "dirs",
+ "fernet",
+ "hex",
+ "passwords",
+ "pbkdf2 0.12.2",
+ "pkcs8",
+ "pyo3",
+ "rand",
+ "schnorrkel",
+ "scrypt",
+ "serde",
+ "serde_json",
+ "sha2 0.10.8",
+ "sodiumoxide",
+ "sp-core",
+]
+
+[[package]]
+name = "bitvec"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
+[[package]]
+name = "blake2"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
+dependencies = [
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "blake2b_simd"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "constant_time_eq",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "block-padding"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
+
+[[package]]
+name = "bounded-collections"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d32385ecb91a31bddaf908e8dcf4a15aef1bcd3913cc03ebfad02ff6d568abc1"
+dependencies = [
+ "log",
+ "parity-scale-codec",
+ "scale-info",
+ "serde",
+]
+
+[[package]]
+name = "bs58"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+
+[[package]]
+name = "byte-slice-cast"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "1.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
+
+[[package]]
+name = "cc"
+version = "1.1.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chrono"
+version = "0.4.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "num-traits",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "cipher"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+]
+
+[[package]]
+name = "colored"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
+dependencies = [
+ "lazy_static",
+ "windows-sys",
+]
+
+[[package]]
+name = "const-oid"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
+
+[[package]]
+name = "constant_time_eq"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
+
+[[package]]
+name = "constcat"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd7e35aee659887cbfb97aaf227ac12cad1a9d7c71e55ff3376839ed4e282d08"
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
+name = "crypto-bigint"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
+dependencies = [
+ "generic-array",
+ "rand_core",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "rand_core",
+ "typenum",
+]
+
+[[package]]
+name = "crypto-mac"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a"
+dependencies = [
+ "generic-array",
+ "subtle",
+]
+
+[[package]]
+name = "ctr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f"
+dependencies = [
+ "cipher 0.2.5",
+]
+
+[[package]]
+name = "curve25519-dalek"
+version = "4.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "curve25519-dalek-derive",
+ "digest 0.10.7",
+ "fiat-crypto",
+ "rustc_version",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "curve25519-dalek-derive"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "der"
+version = "0.7.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
+dependencies = [
+ "const-oid",
+ "zeroize",
+]
+
+[[package]]
+name = "derivative"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "derive_more"
+version = "0.99.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "digest"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer 0.10.4",
+ "const-oid",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "dirs"
+version = "5.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users",
+ "windows-sys",
+]
+
+[[package]]
+name = "dyn-clonable"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4"
+dependencies = [
+ "dyn-clonable-impl",
+ "dyn-clone",
+]
+
+[[package]]
+name = "dyn-clonable-impl"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "dyn-clone"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
+
+[[package]]
+name = "ecdsa"
+version = "0.16.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
+dependencies = [
+ "der",
+ "digest 0.10.7",
+ "elliptic-curve",
+ "rfc6979",
+ "serdect",
+ "signature 2.2.0",
+ "spki",
+]
+
+[[package]]
+name = "ed25519"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
+dependencies = [
+ "signature 1.6.4",
+]
+
+[[package]]
+name = "ed25519"
+version = "2.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
+dependencies = [
+ "pkcs8",
+ "signature 2.2.0",
+]
+
+[[package]]
+name = "ed25519-zebra"
+version = "4.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9"
+dependencies = [
+ "curve25519-dalek",
+ "ed25519 2.2.3",
+ "hashbrown 0.14.5",
+ "hex",
+ "rand_core",
+ "sha2 0.10.8",
+ "zeroize",
+]
+
+[[package]]
+name = "either"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+
+[[package]]
+name = "elliptic-curve"
+version = "0.13.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
+dependencies = [
+ "base16ct",
+ "crypto-bigint",
+ "digest 0.10.7",
+ "ff",
+ "generic-array",
+ "group",
+ "pkcs8",
+ "rand_core",
+ "sec1",
+ "serdect",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "environmental"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b"
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "expander"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2c470c71d91ecbd179935b24170459e926382eaaa86b590b78814e180d8a8e2"
+dependencies = [
+ "blake2",
+ "file-guard",
+ "fs-err",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "fernet"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3364d69f691f3903b1a71605fa04f40a7c2d259f0f0512347e36d19a63debf1f"
+dependencies = [
+ "base64 0.21.7",
+ "byteorder",
+ "getrandom",
+ "openssl",
+ "zeroize",
+]
+
+[[package]]
+name = "ff"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
+dependencies = [
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
+name = "fiat-crypto"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
+
+[[package]]
+name = "file-guard"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21ef72acf95ec3d7dbf61275be556299490a245f017cf084bd23b4f68cf9407c"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "fixed-hash"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534"
+dependencies = [
+ "byteorder",
+ "rand",
+ "rustc-hex",
+ "static_assertions",
+]
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "fs-err"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "funty"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+
+[[package]]
+name = "futures"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+ "num_cpus",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+
+[[package]]
+name = "futures-task"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+
+[[package]]
+name = "futures-util"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+ "zeroize",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "getrandom_or_panic"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ea1015b5a70616b688dc230cfe50c8af89d972cb132d5a622814d29773b10b9"
+dependencies = [
+ "rand",
+ "rand_core",
+]
+
+[[package]]
+name = "group"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
+dependencies = [
+ "ff",
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
+name = "hash-db"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e7d7786361d7425ae2fe4f9e407eb0efaa0840f5212d109cc018c40c35c6ab4"
+
+[[package]]
+name = "hash256-std-hasher"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2"
+dependencies = [
+ "crunchy",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
+dependencies = [
+ "ahash",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+dependencies = [
+ "ahash",
+ "allocator-api2",
+]
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "hex-conservative"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20"
+
+[[package]]
+name = "hmac"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15"
+dependencies = [
+ "crypto-mac",
+ "digest 0.9.0",
+]
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.61"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "impl-codec"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f"
+dependencies = [
+ "parity-scale-codec",
+]
+
+[[package]]
+name = "impl-serde"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "impl-trait-for-tuples"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.14.5",
+]
+
+[[package]]
+name = "indoc"
+version = "2.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
+
+[[package]]
+name = "inout"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itertools"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+
+[[package]]
+name = "js-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "k256"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b"
+dependencies = [
+ "cfg-if",
+ "ecdsa",
+ "elliptic-curve",
+ "once_cell",
+ "serdect",
+ "sha2 0.10.8",
+]
+
+[[package]]
+name = "keccak"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654"
+dependencies = [
+ "cpufeatures",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "libc"
+version = "0.2.159"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
+
+[[package]]
+name = "libredox"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+dependencies = [
+ "bitflags 2.6.0",
+ "libc",
+]
+
+[[package]]
+name = "libsecp256k1"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1"
+dependencies = [
+ "arrayref",
+ "base64 0.13.1",
+ "digest 0.9.0",
+ "libsecp256k1-core",
+ "libsecp256k1-gen-ecmult",
+ "libsecp256k1-gen-genmult",
+ "rand",
+ "serde",
+ "sha2 0.9.9",
+]
+
+[[package]]
+name = "libsecp256k1-core"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451"
+dependencies = [
+ "crunchy",
+ "digest 0.9.0",
+ "subtle",
+]
+
+[[package]]
+name = "libsecp256k1-gen-ecmult"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809"
+dependencies = [
+ "libsecp256k1-core",
+]
+
+[[package]]
+name = "libsecp256k1-gen-genmult"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c"
+dependencies = [
+ "libsecp256k1-core",
+]
+
+[[package]]
+name = "libsodium-sys"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b779387cd56adfbc02ea4a668e704f729be8d6a6abd2c27ca5ee537849a92fd"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "walkdir",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "matchers"
+version = "0.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
+dependencies = [
+ "regex-automata 0.1.10",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "merlin"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d"
+dependencies = [
+ "byteorder",
+ "keccak",
+ "rand_core",
+ "zeroize",
+]
+
+[[package]]
+name = "num-bigint"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
+dependencies = [
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-format"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3"
+dependencies = [
+ "arrayvec",
+ "itoa",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+
+[[package]]
+name = "opaque-debug"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
+
+[[package]]
+name = "openssl"
+version = "0.10.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
+dependencies = [
+ "bitflags 2.6.0",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
+name = "parity-bip39"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e69bf016dc406eff7d53a7d3f7cf1c2e72c82b9088aac1118591e36dd2cd3e9"
+dependencies = [
+ "bitcoin_hashes 0.13.0",
+ "rand",
+ "rand_core",
+ "serde",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "parity-scale-codec"
+version = "3.6.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee"
+dependencies = [
+ "arrayvec",
+ "bitvec",
+ "byte-slice-cast",
+ "bytes",
+ "impl-trait-for-tuples",
+ "parity-scale-codec-derive",
+ "serde",
+]
+
+[[package]]
+name = "parity-scale-codec-derive"
+version = "3.6.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "password-hash"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54986aa4bfc9b98c6a5f40184223658d187159d7b3c6af33f2b2aa25ae1db0fa"
+dependencies = [
+ "base64ct",
+ "rand_core",
+]
+
+[[package]]
+name = "password-hash"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
+dependencies = [
+ "base64ct",
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
+name = "passwords"
+version = "3.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11407193a7c2bd14ec6b0ec3394da6fdcf7a4d5dcbc8c3cc38dfb17802c8d59c"
+dependencies = [
+ "random-pick",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "pbkdf2"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf916dd32dd26297907890d99dc2740e33f6bd9073965af4ccff2967962f5508"
+dependencies = [
+ "base64ct",
+ "crypto-mac",
+ "hmac 0.10.1",
+ "password-hash 0.1.4",
+ "sha2 0.9.9",
+]
+
+[[package]]
+name = "pbkdf2"
+version = "0.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
+dependencies = [
+ "digest 0.10.7",
+ "hmac 0.12.1",
+ "password-hash 0.5.0",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pkcs8"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
+dependencies = [
+ "der",
+ "spki",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
+
+[[package]]
+name = "polkavm-common"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d9428a5cfcc85c5d7b9fc4b6a18c4b802d0173d768182a51cc7751640f08b92"
+
+[[package]]
+name = "polkavm-derive"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae8c4bea6f3e11cd89bb18bcdddac10bd9a24015399bd1c485ad68a985a19606"
+dependencies = [
+ "polkavm-derive-impl-macro",
+]
+
+[[package]]
+name = "polkavm-derive-impl"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c"
+dependencies = [
+ "polkavm-common",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "polkavm-derive-impl-macro"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429"
+dependencies = [
+ "polkavm-derive-impl",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "portable-atomic"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d30538d42559de6b034bc76fd6dd4c38961b1ee5c6c56e3808c50128fdbc22ce"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "prettyplease"
+version = "0.2.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
+dependencies = [
+ "proc-macro2",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "primitive-types"
+version = "0.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2"
+dependencies = [
+ "fixed-hash",
+ "impl-codec",
+ "impl-serde",
+ "scale-info",
+ "uint",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b"
+dependencies = [
+ "toml_edit",
+]
+
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.20+deprecated"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "pyo3"
+version = "0.22.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15ee168e30649f7f234c3d49ef5a7a6cbf5134289bc46c29ff3155fa3221c225"
+dependencies = [
+ "cfg-if",
+ "indoc",
+ "libc",
+ "memoffset",
+ "once_cell",
+ "portable-atomic",
+ "pyo3-build-config",
+ "pyo3-ffi",
+ "pyo3-macros",
+ "unindent",
+]
+
+[[package]]
+name = "pyo3-build-config"
+version = "0.22.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e61cef80755fe9e46bb8a0b8f20752ca7676dcc07a5277d8b7768c6172e529b3"
+dependencies = [
+ "once_cell",
+ "target-lexicon",
+]
+
+[[package]]
+name = "pyo3-ffi"
+version = "0.22.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67ce096073ec5405f5ee2b8b31f03a68e02aa10d5d4f565eca04acc41931fa1c"
+dependencies = [
+ "libc",
+ "pyo3-build-config",
+]
+
+[[package]]
+name = "pyo3-macros"
+version = "0.22.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2440c6d12bc8f3ae39f1e775266fa5122fd0c8891ce7520fa6048e683ad3de28"
+dependencies = [
+ "proc-macro2",
+ "pyo3-macros-backend",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "pyo3-macros-backend"
+version = "0.22.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1be962f0e06da8f8465729ea2cb71a416d2257dff56cbe40a70d3e62a93ae5d1"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "pyo3-build-config",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "radium"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "random-number"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a3da5cbb4c27c5150c03a54a7e4745437cd90f9e329ae657c0b889a144bb7be"
+dependencies = [
+ "proc-macro-hack",
+ "rand",
+ "random-number-macro-impl",
+]
+
+[[package]]
+name = "random-number-macro-impl"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b86292cf41ccfc96c5de7165c1c53d5b4ac540c5bab9d1857acbe9eba5f1a0b"
+dependencies = [
+ "proc-macro-hack",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "random-pick"
+version = "1.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c179499072da789afe44127d5f4aa6012de2c2f96ef759990196b37387a2a0f8"
+dependencies = [
+ "random-number",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853"
+dependencies = [
+ "bitflags 2.6.0",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
+dependencies = [
+ "getrandom",
+ "libredox",
+ "thiserror",
+]
+
+[[package]]
+name = "ref-cast"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931"
+dependencies = [
+ "ref-cast-impl",
+]
+
+[[package]]
+name = "ref-cast-impl"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "regex"
+version = "1.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata 0.4.7",
+ "regex-syntax 0.8.4",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
+dependencies = [
+ "regex-syntax 0.6.29",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax 0.8.4",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+
+[[package]]
+name = "rfc6979"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
+dependencies = [
+ "hmac 0.12.1",
+ "subtle",
+]
+
+[[package]]
+name = "rustc-hex"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "salsa20"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213"
+dependencies = [
+ "cipher 0.4.4",
+]
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "scale-info"
+version = "2.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024"
+dependencies = [
+ "bitvec",
+ "cfg-if",
+ "derive_more",
+ "parity-scale-codec",
+ "scale-info-derive",
+ "serde",
+]
+
+[[package]]
+name = "scale-info-derive"
+version = "2.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "schnorrkel"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8de18f6d8ba0aad7045f5feae07ec29899c1112584a38509a84ad7b04451eaa0"
+dependencies = [
+ "aead",
+ "arrayref",
+ "arrayvec",
+ "curve25519-dalek",
+ "getrandom_or_panic",
+ "merlin",
+ "rand_core",
+ "serde_bytes",
+ "sha2 0.10.8",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "scrypt"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f"
+dependencies = [
+ "password-hash 0.5.0",
+ "pbkdf2 0.12.2",
+ "salsa20",
+ "sha2 0.10.8",
+]
+
+[[package]]
+name = "sec1"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
+dependencies = [
+ "base16ct",
+ "der",
+ "generic-array",
+ "pkcs8",
+ "serdect",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "secp256k1"
+version = "0.28.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10"
+dependencies = [
+ "secp256k1-sys",
+]
+
+[[package]]
+name = "secp256k1-sys"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "secrecy"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e"
+dependencies = [
+ "zeroize",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+
+[[package]]
+name = "serde"
+version = "1.0.210"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.210"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.128"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serdect"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177"
+dependencies = [
+ "base16ct",
+ "serde",
+]
+
+[[package]]
+name = "sha2"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
+dependencies = [
+ "block-buffer 0.9.0",
+ "cfg-if",
+ "cpufeatures",
+ "digest 0.9.0",
+ "opaque-debug",
+]
+
+[[package]]
+name = "sha2"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "sha3"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
+dependencies = [
+ "digest 0.10.7",
+ "keccak",
+]
+
+[[package]]
+name = "sharded-slab"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "signature"
+version = "1.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
+
+[[package]]
+name = "signature"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
+dependencies = [
+ "digest 0.10.7",
+ "rand_core",
+]
+
+[[package]]
+name = "slab"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
+[[package]]
+name = "sodiumoxide"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e26be3acb6c2d9a7aac28482586a7856436af4cfe7100031d219de2d2ecb0028"
+dependencies = [
+ "ed25519 1.5.3",
+ "libc",
+ "libsodium-sys",
+ "serde",
+]
+
+[[package]]
+name = "sp-core"
+version = "34.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c961a5e33fb2962fa775c044ceba43df9c6f917e2c35d63bfe23738468fa76a7"
+dependencies = [
+ "array-bytes",
+ "bitflags 1.3.2",
+ "blake2",
+ "bounded-collections",
+ "bs58",
+ "dyn-clonable",
+ "ed25519-zebra",
+ "futures",
+ "hash-db",
+ "hash256-std-hasher",
+ "impl-serde",
+ "itertools 0.11.0",
+ "k256",
+ "libsecp256k1",
+ "log",
+ "merlin",
+ "parity-bip39",
+ "parity-scale-codec",
+ "parking_lot",
+ "paste",
+ "primitive-types",
+ "rand",
+ "scale-info",
+ "schnorrkel",
+ "secp256k1",
+ "secrecy",
+ "serde",
+ "sp-crypto-hashing",
+ "sp-debug-derive",
+ "sp-externalities",
+ "sp-runtime-interface",
+ "sp-std",
+ "sp-storage",
+ "ss58-registry",
+ "substrate-bip39",
+ "thiserror",
+ "tracing",
+ "w3f-bls",
+ "zeroize",
+]
+
+[[package]]
+name = "sp-crypto-hashing"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc9927a7f81334ed5b8a98a4a978c81324d12bd9713ec76b5c68fd410174c5eb"
+dependencies = [
+ "blake2b_simd",
+ "byteorder",
+ "digest 0.10.7",
+ "sha2 0.10.8",
+ "sha3",
+ "twox-hash",
+]
+
+[[package]]
+name = "sp-debug-derive"
+version = "14.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "sp-externalities"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a904407d61cb94228c71b55a9d3708e9d6558991f9e83bd42bd91df37a159d30"
+dependencies = [
+ "environmental",
+ "parity-scale-codec",
+ "sp-storage",
+]
+
+[[package]]
+name = "sp-runtime-interface"
+version = "28.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "985eb981f40c689c6a0012c937b68ed58dabb4341d06f2dfe4dfd5ed72fa4017"
+dependencies = [
+ "bytes",
+ "impl-trait-for-tuples",
+ "parity-scale-codec",
+ "polkavm-derive",
+ "primitive-types",
+ "sp-externalities",
+ "sp-runtime-interface-proc-macro",
+ "sp-std",
+ "sp-storage",
+ "sp-tracing",
+ "sp-wasm-interface",
+ "static_assertions",
+]
+
+[[package]]
+name = "sp-runtime-interface-proc-macro"
+version = "18.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0195f32c628fee3ce1dfbbf2e7e52a30ea85f3589da9fe62a8b816d70fc06294"
+dependencies = [
+ "Inflector",
+ "expander",
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "sp-std"
+version = "14.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12f8ee986414b0a9ad741776762f4083cd3a5128449b982a3919c4df36874834"
+
+[[package]]
+name = "sp-storage"
+version = "21.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99c82989b3a4979a7e1ad848aad9f5d0b4388f1f454cc131766526601ab9e8f8"
+dependencies = [
+ "impl-serde",
+ "parity-scale-codec",
+ "ref-cast",
+ "serde",
+ "sp-debug-derive",
+]
+
+[[package]]
+name = "sp-tracing"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90b3decf116db9f1dfaf1f1597096b043d0e12c952d3bcdc018c6d6b77deec7e"
+dependencies = [
+ "parity-scale-codec",
+ "tracing",
+ "tracing-core",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "sp-wasm-interface"
+version = "21.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b04b919e150b4736d85089d49327eab65507deb1485eec929af69daa2278eb3"
+dependencies = [
+ "impl-trait-for-tuples",
+ "log",
+ "parity-scale-codec",
+]
+
+[[package]]
+name = "spki"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
+dependencies = [
+ "base64ct",
+ "der",
+]
+
+[[package]]
+name = "ss58-registry"
+version = "1.50.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43fce22ed1df64d04b262351c8f9d5c6da4f76f79f25ad15529792f893fad25d"
+dependencies = [
+ "Inflector",
+ "num-format",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "unicode-xid",
+]
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "substrate-bip39"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca58ffd742f693dc13d69bdbb2e642ae239e0053f6aab3b104252892f856700a"
+dependencies = [
+ "hmac 0.12.1",
+ "pbkdf2 0.12.2",
+ "schnorrkel",
+ "sha2 0.10.8",
+ "zeroize",
+]
+
+[[package]]
+name = "subtle"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
+[[package]]
+name = "target-lexicon"
+version = "0.12.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
+
+[[package]]
+name = "thiserror"
+version = "1.0.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+
+[[package]]
+name = "toml_edit"
+version = "0.22.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "tracing"
+version = "0.1.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2"
+dependencies = [
+ "log",
+ "once_cell",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-serde"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1"
+dependencies = [
+ "serde",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71"
+dependencies = [
+ "ansi_term",
+ "chrono",
+ "lazy_static",
+ "matchers",
+ "regex",
+ "serde",
+ "serde_json",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+ "tracing-serde",
+]
+
+[[package]]
+name = "twox-hash"
+version = "1.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
+dependencies = [
+ "cfg-if",
+ "digest 0.10.7",
+ "rand",
+ "static_assertions",
+]
+
+[[package]]
+name = "typenum"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+
+[[package]]
+name = "uint"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52"
+dependencies = [
+ "byteorder",
+ "crunchy",
+ "hex",
+ "static_assertions",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+
+[[package]]
+name = "unindent"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
+
+[[package]]
+name = "valuable"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "w3f-bls"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c5da5fa2c6afa2c9158eaa7cd9aee249765eb32b5fb0c63ad8b9e79336a47ec"
+dependencies = [
+ "ark-bls12-377",
+ "ark-bls12-381",
+ "ark-ec",
+ "ark-ff",
+ "ark-serialize",
+ "ark-serialize-derive",
+ "arrayref",
+ "constcat",
+ "digest 0.10.7",
+ "rand",
+ "rand_chacha",
+ "rand_core",
+ "sha2 0.10.8",
+ "sha3",
+ "thiserror",
+ "zeroize",
+]
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-core"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winnow"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "wyz"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
+dependencies = [
+ "tap",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+dependencies = [
+ "byteorder",
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..95e1ab9
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,33 @@
+[package]
+name = "bittensor_wallet"
+version = "2.0.0"
+edition = "2021"
+
+[lib]
+name = "bittensor_wallet"
+crate-type = ["cdylib"]
+
+[dependencies]
+sp-core = "34.0.0"
+pyo3 = { version = "0.22.3", features = ["gil-refs"] }
+bip39 = { version = "2.0.0", features = ["rand"] }
+rand = "0.8.5"
+hex = "0.4.3"
+colored = "2.1.0"
+serde_json = "1.0.128"
+passwords = "3.1.16"
+sodiumoxide = "0.2"
+ansible-vault = "0.2.1"
+fernet = "=0.2.1"
+pbkdf2 = "0.12.2"
+sha2 = "0.10.8"
+dirs = "5.0.1"
+serde = { version = "1.0.210", features = ["derive"] }
+base64 = "0.22.1"
+scrypt = "0.11.0"
+pkcs8 = "0.10.2"
+schnorrkel = "0.11.4"
+
+[features]
+extension-module = ["pyo3/extension-module"]
+default = ["extension-module"]
diff --git a/README.md b/README.md
index 803abbb..8c012e3 100644
--- a/README.md
+++ b/README.md
@@ -1,30 +1,95 @@
+<div align="center">
+
+# Bittensor Wallet SDK <!-- omit in toc -->
+
+[![Discord Chat](https://img.shields.io/discord/308323056592486420.svg)](https://discord.gg/bittensor)
+[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
+[![PyPI version](https://badge.fury.io/py/bittensor-wallet.svg)](https://badge.fury.io/py/bittensor-wallet)
+
+---
+
+## Internet-scale Neural Networks <!-- omit in toc -->
+
+[Bittensor SDK](https://github.com/opentensor/bittensor/tree/master) • [BTCLI](https://github.com/opentensor/btcli) • [Research](https://bittensor.com/whitepaper)
+
+</div>
+
 ## Bittensor Wallet SDK
 
-# Install
-There are a few ways to install Bittensor
+The Bittensor Wallet SDK is a Python interface for a powerful Rust-based Bittensor wallet functionality. You do not need to know Rust to use this Wallet SDK. However, if you want to contribute to the Rust components of this Wallet SDK, the Rust source is located in the [src](./src) directory.
+
+## Documentation
+
+For a full documentation on how to use `btwallet`, see the [Bittensor Wallet SDK section](https://docs.bittensor.com/btcli) on the developer documentation site.
+
+---
+
+## Before you proceed
+
+1. If you installed either Bittensor SDK version `8.1.0` or BTCLI version `8.1.0` then the Wallet SDK 2.0.0 is already installed. The below installation steps are only for a standalone installation of the Wallet SDK 2.0.0 package.
+2. **IMPORTANT**: The Wallet SDK 2.0.0 is compatible only with Bittensor SDK version `8.1.0` and later versions and BTCLI version `8.1.0` and later versions. Earlier versions of Bittensor SDK and BTCLI are not compatible with Wallet SDK 2.0.0.
+
+## Install
+
+Follow the below steps to install the Bittensor Wallet SDK:
+
+### From PyPI
+
+Use this option if you want to use the Wallet SDK.
 
-1. From source for usage:
 ```bash
-$ git clone https://github.com/opentensor/btwallet.git
-$ python3 -m pip install -e bittensor_wallet/
+$ python3 -m venv btwallet-venv  # create a virtual env
+$ source btwallet-venv/bin/activate  # activate the env
+$ pip install bittensor-wallet  # install bittensor-wallet
 ```
-2. From source for development needs:
+
+### From source
+
+Use this option if you want to develop your application using the Wallet SDK.
+
 ```bash
-$ git clone https://github.com/opentensor/btwallet.git
-$ python3 -m venv venv  # create env
-$ source venv/bin/activate  # activate env
-$ pip install bittensor-wallet  # install bittensor-wallet
-$ python3 -m pip install -e .[dev] # installs dependencies for development and testing
+python3 -m venv btwallet-venv  # create a virtual env
+source venv/bin/activate  # activate the env
+git clone https://github.com/opentensor/btwallet.git
+cd btwallet
+pip install maturin
+maturin develop
 ```
 
-3. From PyPI:
+After the `maturin develop` command completes, run the below command:
+
 ```bash
-$ python3 -m venv venv  # create env
-$ source venv/bin/activate  # activate env
-$ pip install bittensor-wallet  # install bittensor-wallet
+pip list
 ```
 
-# To test your installation using python
+You will see `bittensor-wallet` in the list on installed packages. This means the installation was successful.
+
+---
+
+## Verify your installation
+
+In the `python3` interpreter, run the below code to verify that your installation was successful. See an example output below:
+
+```bash
+python3
+Python 3.12.4 (v3.12.4:8e8a4baf65, Jun  6 2024, 17:33:18) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> import bittensor_wallet
+>>> print(bittensor_wallet.__version__)
+2.0.0
+>>>
+```
+
+The above will print the Wallet SDK version you just installed, i.e., `2.0.0`, confirming that the installation was successful.
+
+---
+
+## Usage examples
+
+**1. Create a wallet**
+
+In the `python3` interpreter, run the below code:
+
 ```python
 from bittensor_wallet import Wallet
 
@@ -32,16 +97,71 @@ from bittensor_wallet import Wallet
 wallet = Wallet()
 wallet.create()
 ```
-If you want to pass arguments to the class other than the default, use the following:
-```python
+
+If a wallet with the name "default" already exists, then you will see a message. If it doesn't exist, then the above code will create both a coldkey and a hotkey and displays the following information, including your mnemonic **(mnemonics are replaced with `x` in the below example for security)**:
+
+```
+IMPORTANT: Store this mnemonic in a secure (preferable offline place), as anyone who has possession of this mnemonic can use it to regenerate the key and access your tokens.
+
+The mnemonic to the new coldkey is:
+
+forward xxxx xxx xxx xxxx xxxx xxxx xxx xx xx xx actress
+
+You can use the mnemonic to recreate the key in case it gets lost. The command to use to regenerate the key using this mnemonic is:
+btcli w regen-coldkey --mnemonic "forward xxxx xxx xxx xxxx xxxx xxxx xxx xx xx xx actress"
+
+Specify password for key encryption:
+Retype your password:
+
+IMPORTANT: Store this mnemonic in a secure (preferable offline place), as anyone who has possession of this mnemonic can use it to regenerate the key and access your tokens.
+
+The mnemonic to the new hotkey is:
+
+fuel xxxx xxx xxx xxxx xxxx xxxx xxx xx xx xxx bind
+
+You can use the mnemonic to recreate the key in case it gets lost. The command to use to regenerate the key using this mnemonic is:
+btcli w regen-hotkey --mnemonic "fuel xxxx xxx xxx xxxx xxxx xxxx xxx xx xx xxx bind"
+
+name: 'default', hotkey: 'default', path: '~/.bittensor/wallets/'
+>>> print(wallet)
+Wallet (Name: 'default', Hotkey: 'default', Path: '~/.bittensor/wallets/')
+>>>
+```
+
+**2. Pass arguments to a class other than the default**
+
+```
 name (str): The name of the wallet, used to identify it among possibly multiple wallets.
 hotkey (str): String identifier for the hotkey.
 path (str): File system path where wallet keys are stored.
 config (Config): Bittensor configuration object.
 ```
 
-To use your own config, you can do it like this:
+In the `python3` interpreter, run the below code. See an example below (only partial is shown):
+
+```bash
+python3
+Python 3.12.4 (v3.12.4:8e8a4baf65, Jun  6 2024, 17:33:18) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> from bittensor_wallet import Wallet
+>>> my_name = "my_wallet_name"
+>>> my_path = "path_to_my_wallet"
+>>> my_hotkey = "name_of_my_hotkey"
+>>>
+>>> my_wallet = Wallet(name=my_name, path=my_path, hotkey=my_hotkey)
+>>> my_wallet.create()
+
+IMPORTANT: Store this mnemonic in a secure (preferable offline place), as anyone who has possession of this mnemonic can use it to regenerate the key and access your tokens.
+
+```
+
+The above will create a wallet with "my_wallet_name". 
+
+**3. Use your own config**
+
 ```python
 from bittensor_wallet.config import Config
 config = Config()
 ```
+
+---
diff --git a/RUST-README.md b/RUST-README.md
new file mode 100644
index 0000000..8b7396b
--- /dev/null
+++ b/RUST-README.md
@@ -0,0 +1,309 @@
+<div align="center">
+
+# Rust Components for Bittensor Wallet SDK <!-- omit in toc -->
+
+[![Discord Chat](https://img.shields.io/discord/308323056592486420.svg)](https://discord.gg/bittensor)
+[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
+[![PyPI version](https://badge.fury.io/py/bittensor-wallet.svg)](https://badge.fury.io/py/bittensor-wallet)
+
+---
+
+## Internet-scale Neural Networks <!-- omit in toc -->
+
+[Bittensor SDK](https://github.com/opentensor/bittensor/tree/master) • [BTCLI](https://github.com/opentensor/btcli) • [Research](https://bittensor.com/whitepaper)
+
+</div>
+
+The Bittensor Wallet SDK is a Python interface for a powerful Rust-based Bittensor wallet functionality. You do not need to know Rust to use this Wallet SDK. However, if you want to contribute to the Rust components of this Wallet SDK, the Rust source is located in the [src](./src) directory.
+
+## Documentation
+
+For a full documentation for `btwallet` Python SDK see the [Bittensor Wallet SDK section](https://docs.bittensor.com/btcli) on the developer documentation site.
+
+## Rust Development
+
+To build and test the Rust components of the project, you can use the following commands:
+* `maturin develop` - Builds the project.
+* `cargo test` - Runs the tests.
+* `cargo run` - Runs the project.
+* `cargo doc --open` - Generates the documentation and opens it in the browser.
+* `cargo fmt` - Formats the code.
+* `cargo clippy` - Runs the linter.
+* `cargo clippy --fix` - Fixes the code.
+
+## Using the Rust components in Python
+
+```python
+from bittensor_wallet import config, errors, keyfile, keypair, utils, wallet
+
+print(utils.SS58_FORMAT)
+
+myconf = config.Config()
+print(myconf)
+
+mywallet = wallet.Wallet(config=myconf)
+print(mywallet)
+
+try: 
+    mywallet.unlock_coldkey()
+    mywallet.unlock_coldkeypub()
+    mywallet.unlock_hotkey()
+except errors.KeyFileError:
+    print("Failed unlocking.")
+```
+
+## keypair::KeyPair
+
+### Tests for Keypair
+```python
+from bittensor_wallet import Keypair as WKeypair
+from substrateinterface import Keypair as SKeypair
+
+kps = SKeypair.create_from_mnemonic("stool feel open east woman high can denial forget screen trust salt")
+kpw = WKeypair.create_from_mnemonic("stool feel open east woman high can denial forget screen trust salt")
+assert kps.ss58_address == kpw.ss58_address
+assert kps.seed_hex == kpw.seed_hex
+assert kps.public_key == kpw.public_key
+assert kps.private_key == kpw.private_key
+
+kps = SKeypair.create_from_seed("0x023d5fbd7981676587a9f7232aeae1087ac7c265f9658fb643b6f5e61961dfbf")
+kpw = WKeypair.create_from_seed("0x023d5fbd7981676587a9f7232aeae1087ac7c265f9658fb643b6f5e61961dfbf")
+assert kps.ss58_address == kpw.ss58_address
+assert kps.seed_hex == kpw.seed_hex
+assert kps.public_key == kpw.public_key
+assert kps.private_key == kpw.private_key
+
+# substrateinterface has a bug -> can't create the KP without `ss58_format` passed
+kps = SKeypair.create_from_private_key("0x2b400f61c21cbaad4d5cb2dcbb4ef4fcdc238b98d04d48c6d2a451ebfd306c0eed845edcc69b0a19a6905afed0dd84c16ebd0f458928f2e91a6b67b95fc0b42f", ss58_format=42)
+kpw = WKeypair.create_from_private_key("0x2b400f61c21cbaad4d5cb2dcbb4ef4fcdc238b98d04d48c6d2a451ebfd306c0eed845edcc69b0a19a6905afed0dd84c16ebd0f458928f2e91a6b67b95fc0b42f")
+assert kps.ss58_address == kpw.ss58_address
+assert kps.seed_hex == kpw.seed_hex
+assert kps.public_key == kpw.public_key
+assert kps.private_key == kpw.private_key
+
+kps = SKeypair.create_from_uri("//Alice")
+kpw = WKeypair.create_from_uri("//Alice")
+assert kps.ss58_address == kpw.ss58_address
+assert kps.seed_hex == kpw.seed_hex
+assert kps.public_key == kpw.public_key
+assert kps.private_key == kpw.private_key
+
+# substrateinterface has a bug -> can't create the KP without `ss58_format` passed
+from_private_key_new_kps = SKeypair(public_key=kps.public_key.hex(), ss58_format=42)
+from_private_key_new_kpw = WKeypair(public_key=kps.public_key.hex())
+assert from_private_key_new_kps.ss58_address == from_private_key_new_kpw.ss58_address
+assert from_private_key_new_kps.seed_hex == from_private_key_new_kpw.seed_hex
+assert from_private_key_new_kps.public_key == from_private_key_new_kpw.public_key
+assert from_private_key_new_kps.private_key == from_private_key_new_kpw.private_key
+
+from_address_kps = SKeypair(ss58_address="5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY")
+from_address_kpw = WKeypair(ss58_address="5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY")
+assert from_address_kps.ss58_address == from_address_kpw.ss58_address
+assert from_address_kps.seed_hex == from_address_kpw.seed_hex
+assert from_address_kps.public_key == from_address_kpw.public_key
+assert from_address_kps.private_key == from_address_kpw.private_key
+
+# check signature
+assert kps.verify("asd", kpw.sign("asd")) == True
+
+# check verify
+assert kpw.verify("asd", kps.sign("asd")) == True
+
+# check create_from_encrypted_json
+from substrateinterface.base import Keypair as S_Keypair
+from bittensor_wallet import Keypair as W_Keypair
+
+data = '{"encoded":"Z1yzxASuj21ej3CANbZKc3ibDaOpQPMahTT0qkniyZgAgAAAAQAAAAgAAACSDgflXWKXrX36EmX9XcA6cRpkN+oZX30/9FhtNP17krIG/yHLKmDnL1km1W/nZ+BpC7Qid6IuBvbZeboFyewFeXsKtcoY/bRY6nx/cLB5BND9WpXXS6Enf4RXAX7vPu/BY+o2z7VwPaXyFARfyPTiqJKqLDJWm3W5ZlvK0ks8FBv66mWEBYc+lLx8jvuzDNkdD3pnV3G802OwwHTy","encoding":{"content":["pkcs8","sr25519"],"type":["scrypt","xsalsa20-poly1305"],"version":"3"},"address":"5CuByUQBWZci5AtXonuHHhcbRL3yxM5xDdJsTNaYN3vPDY6f","meta":{"genesisHash":null,"name":"test","whenCreated":1727395683981}}'
+passphrase = "Password123"
+
+skp = S_Keypair.create_from_encrypted_json(data, passphrase)
+wkp = W_Keypair.create_from_encrypted_json(data, passphrase)
+
+assert skp.ss58_format == wkp.ss58_format
+assert skp.private_key == wkp.private_key
+assert skp.private_key.hex() == wkp.private_key.hex()
+assert skp.public_key == wkp.public_key
+assert skp.public_key.hex() == wkp.public_key.hex()
+```
+### Check signature and verify with ScaleBytes
+```python
+from scalecodec.base import ScaleBytes
+from bittensor_wallet import Keypair as WKeypair
+from substrateinterface import Keypair as SKeypair
+
+kps = SKeypair.create_from_uri("//Alice")
+kpw = WKeypair.create_from_uri("//Alice")
+
+message = ScaleBytes(b"my message")
+
+# cross check
+assert kps.verify(message, kpw.sign(message)) == True
+assert kpw.verify(message, kps.sign(message)) == True
+
+# itself check
+assert kpw.verify(message, kpw.sign(message)) == True
+assert kps.verify(message, kps.sign(message)) == True
+```
+## utils.rs
+
+### Tests for utils' functions
+```python
+# check utils functions
+from bittensor_wallet import get_ss58_format, is_valid_ss58_address, is_valid_ed25519_pubkey, is_valid_bittensor_address_or_public_key
+
+# check get_ss58_format
+assert get_ss58_format("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY") == 42
+
+# check is_valid_ss58_address
+assert is_valid_ss58_address("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY") == True
+assert is_valid_ss58_address("blabla") == False
+
+# check is_valid_ed25519_pubkey
+assert is_valid_ed25519_pubkey("a"*64) == True
+assert is_valid_ed25519_pubkey("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY") == False
+assert is_valid_ed25519_pubkey("0x86eb46a3f42935d901acc3b8910ca301d969b76cfc2a80f0eac733a8eda7ed24") == True
+assert is_valid_ed25519_pubkey("86eb46a3f42935d901acc3b8910ca301d969b76cfc2a80f0eac733a8eda7ed24") == True
+assert is_valid_ed25519_pubkey("") ==  False
+try:
+        is_valid_ed25519_pubkey()
+except TypeError:
+        # TypeError: is_valid_ed25519_pubkey() missing 1 required positional argument: 'public_key'
+        ...
+# check is_valid_bittensor_address_or_public_key
+assert is_valid_bittensor_address_or_public_key("blabla") == False
+assert is_valid_bittensor_address_or_public_key("a"*64) == False
+assert is_valid_bittensor_address_or_public_key(b"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY") == False
+assert is_valid_bittensor_address_or_public_key("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY") == True
+assert is_valid_bittensor_address_or_public_key(100) == False
+```
+
+## keyfile.rs
+
+### Tests for keyfile.rs functions
+
+#### Test serialization and deserialization 
+```python
+from bittensor_wallet import Keyfile, Keypair, serialized_keypair_to_keyfile_data, deserialize_keypair_from_keyfile_data
+kp = Keypair.create_from_mnemonic("stool feel open east woman high can denial forget screen trust salt")
+kf_data = serialized_keypair_to_keyfile_data(kp)
+assert isinstance(kf_data, bytes)
+kp_2 = deserialize_keypair_from_keyfile_data(kf_data)
+assert isinstance(kp_2, Keypair)
+assert kp.ss58_address == kp_2.ss58_address
+assert kp.seed_hex == kp_2.seed_hex
+assert kp.public_key == kp_2.public_key
+assert kp.private_key == kp_2.private_key
+```
+
+#### Test Keyfile encrypt and decrypt
+```python
+# test keyfile encryption and decryption 
+from bittensor_wallet import Keyfile
+#KF is an already encrypted key
+kf = Keyfile("/Users/daniel/.bittensor/wallets/game_wallet/coldkey", name="default")
+assert kf.data[:5] == b"$NACL"
+kf.decrypt("testing")
+#Decrypt data...
+assert kf.data[1:13] == b'"publicKey":'
+kf.encrypt("testing")
+#Encryption data...
+assert kf.data[:5] == b"$NACL"
+```
+
+#### Test Keyfile validate_password and ask_password
+```python
+from bittensor_wallet import validate_password, ask_password
+ask_password()
+    #Specify password for key encryption: {password specified here}
+validate_password("test")
+    # False, Password not strong enough
+validate_password("asdf45as6d4f52asd6f54")
+    # True
+```
+
+
+#### Test Keyfile keyfile_data_is_encrypted and keyfile_data_encryption_method
+```python
+from bittensor_wallet import Keyfile, keyfile_data_is_encrypted, keyfile_data_encryption_method
+#KF is an already encrypted key NACL
+kf = Keyfile("/Users/daniel/.bittensor/wallets/game_wallet/coldkey", name="default")
+assert keyfile_data_is_encrypted(kf.data) == True
+assert keyfile_data_encryption_method(kf.data) == 'NaCl'
+```
+
+#### Test Keyfile legacy_encrypt_keyfile_data and keyfile_data_encryption_method
+```python
+from bittensor_wallet import Keyfile, keyfile_data_is_encrypted, keyfile_data_encryption_method, legacy_encrypt_keyfile_data
+#KF is an already encrypted key NACL
+kf = Keyfile("/Users/daniel/.bittensor/wallets/validator/coldkey", name="default")
+assert keyfile_data_is_encrypted(kf.data) == False
+legacy_enc_kf_data = legacy_encrypt_keyfile_data(kf.data, "testing")
+    # :exclamation_mark: Encrypting key with legacy encryption method...
+assert keyfile_data_encryption_method(legacy_enc_kf_data) == 'Ansible Vault'
+```
+
+#### Test Keyfile get_coldkey_password_from_environment
+```python
+import os
+from bittensor_wallet import get_coldkey_password_from_environment
+assert get_coldkey_password_from_environment("some-pw") == None
+os.environ["BT_COLD_PW_SOME_PW"] = "SOMEPASSWORD"
+assert get_coldkey_password_from_environment("some-pw") == "SOMEPASSWORD"
+```
+
+
+#### Test Keyfile encrypt_keyfile_data and decrypt_keyfile_data
+```python
+from bittensor_wallet import Keyfile, decrypt_keyfile_data, encrypt_keyfile_data, keyfile_data_is_encrypted
+kf = Keyfile("/Users/daniel/.bittensor/wallets/validator/coldkey", name="default")
+assert keyfile_data_is_encrypted(kf.data) == False
+encrypted_kf_data = encrypt_keyfile_data(kf.data, "somePassword")
+    #Encryption data...
+assert keyfile_data_is_encrypted(encrypted_kf_data) == True
+decrypted_kf_data = decrypt_keyfile_data(encrypted_kf_data, "somePassword")
+    #Decrypt data...
+assert decrypted_kf_data == kf.data
+```
+
+### Tests for keyfile::Keyfile
+
+#### Test Keyfile is_encrypted, decrypt, encrypt and check_and_update_encryption
+```python
+from bittensor_wallet import Keyfile, Keypair
+kf = Keyfile("/Users/daniel/.bittensor/wallets/newkeyfile", name="default")
+kp = Keypair.create_from_mnemonic("stool feel open east woman high can denial forget screen trust salt")
+kf.set_keypair(kp, False, False)
+
+assert kf.is_encrypted() == False
+kf.encrypt("somepassword")
+    #Encryption data...
+    
+assert kf.is_encrypted() == True
+
+kf.decrypt("somepassword")
+    #Decrypt data...
+
+assert kf.is_encrypted() == False
+
+kf.check_and_update_encryption(True, True)
+    #Keyfile is not encrypted.
+    #False
+```
+
+#### Test Keyfile make_dirs, is_writable, is_readable, get_keypair and exists_on_device
+```python
+from bittensor_wallet import Keyfile, Keypair
+kf = Keyfile("/Users/daniel/.bittensor/wallets/newkeyfile", name="default")
+kp = Keypair.create_from_mnemonic("stool feel open east woman high can denial forget screen trust salt")
+kf.set_keypair(kp, False, False)
+
+assert kf.exists_on_device() == False
+assert kf.is_writable() == False
+assert kf.is_readable() == False
+
+kf.make_dirs()
+
+assert kf.exists_on_device() == True
+assert kf.is_writable() == True
+assert kf.is_readable() == True
+```
\ No newline at end of file
diff --git a/bittensor_wallet/__init__.py b/bittensor_wallet/__init__.py
index 3c87740..eb5c5fb 100644
--- a/bittensor_wallet/__init__.py
+++ b/bittensor_wallet/__init__.py
@@ -1,23 +1,14 @@
-# The MIT License (MIT)
-# Copyright © 2024 Opentensor Foundation
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
-# documentation files (the “Software”), to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
-
-from .wallet import Wallet
-
-
-__version__ = "1.0.0"
-
-__all__ = ["Wallet", "__version__"]
+from bittensor_wallet.bittensor_wallet import (
+    Config as Config,
+    Keyfile as Keyfile,
+    Keypair as Keypair,
+    Wallet as Wallet,
+    utils as utils,
+    config as config,
+    errors as errors,
+    keypair as keypair,
+    keyfile as keyfile,
+    wallet as wallet,
+)
+
+__version__ = "2.0.0"
diff --git a/bittensor_wallet/config.py b/bittensor_wallet/config.py
deleted file mode 100644
index a87863b..0000000
--- a/bittensor_wallet/config.py
+++ /dev/null
@@ -1,408 +0,0 @@
-# The MIT License (MIT)
-# Copyright © 2024 Opentensor Foundation
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
-# documentation files (the “Software”), to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
-
-"""Implementation of the config class, which manages the configuration of different Bittensor modules."""
-
-import argparse
-import copy
-import os
-import sys
-from copy import deepcopy
-from typing import List, Optional, Dict, Any, TypeVar, Type
-
-import yaml
-from munch import DefaultMunch
-
-
-class InvalidConfigFile(Exception):
-    """In place of YAMLError"""
-
-
-class Config(DefaultMunch):
-    """Implementation of the config class, which manages the configuration of different Bittensor modules."""
-
-    __is_set: Dict[str, bool]
-
-    """ 
-    Translates the passed parser into a nested Bittensor config.
-    
-        Args:
-            parser (argparse.ArgumentParser):
-                Command line parser object.
-            strict (bool):
-                If ``true``, the command line arguments are strictly parsed.
-            args (list of str):
-                Command line arguments.
-            default (Optional[Any]):
-                Default value for the Config. Defaults to ``None``.
-                This default will be returned for attributes that are undefined.
-        Returns:
-            config (Config):
-                Nested config object created from parser arguments.
-    """
-
-    def __init__(
-        self,
-        parser: argparse.ArgumentParser = None,
-        args: Optional[List[str]] = None,
-        strict: bool = False,
-        default: Optional[Any] = None,
-    ) -> None:
-        super().__init__(default)
-
-        self["__is_set"] = {}
-
-        if parser is None:
-            return
-
-        # Optionally add config specific arguments
-        try:
-            parser.add_argument(
-                "--config",
-                type=str,
-                help="If set, defaults are overridden by passed file.",
-            )
-        except Exception:
-            # this can fail if --config has already been added.
-            pass
-
-        try:
-            parser.add_argument(
-                "--strict",
-                action="store_true",
-                help="""If flagged, config will check that only exact arguments have been set.""",
-                default=False,
-            )
-        except Exception:
-            # this can fail if --strict has already been added.
-            pass
-
-        try:
-            parser.add_argument(
-                "--no_version_checking",
-                action="store_true",
-                help="Set ``true`` to stop cli version checking.",
-                default=False,
-            )
-        except Exception:
-            # this can fail if --no_version_checking has already been added.
-            pass
-
-        try:
-            parser.add_argument(
-                "--no_prompt",
-                dest="no_prompt",
-                action="store_true",
-                help="Set ``true`` to stop cli from prompting the user.",
-                default=False,
-            )
-        except Exception:
-            # this can fail if --no_version_checking has already been added.
-            pass
-
-        # Get args from argv if not passed in.
-        if args is None:
-            args = sys.argv[1:]
-
-        # Check for missing required arguments before proceeding
-        missing_required_args = self.__check_for_missing_required_args(parser, args)
-        if missing_required_args:
-            # Handle missing required arguments gracefully
-            raise ValueError(
-                f"Missing required arguments: {', '.join(missing_required_args)}"
-            )
-
-        # 1.1 Optionally load defaults if the --config is set.
-        try:
-            config_file_path = (
-                str(os.getcwd())
-                + "/"
-                + vars(parser.parse_known_args(args)[0])["config"]
-            )
-        except Exception:
-            config_file_path = None
-
-        # Parse args not strict
-        config_params = Config.__parse_args__(args=args, parser=parser, strict=False)
-
-        # 2. Optionally check for --strict
-        # strict=True when passed in OR when --strict is set
-        strict = config_params.strict or strict
-
-        if config_file_path is not None:
-            config_file_path = os.path.expanduser(config_file_path)
-            try:
-                with open(config_file_path) as f:
-                    params_config = yaml.safe_load(f)
-                    print("Loading config defaults from: {}".format(config_file_path))
-                    parser.set_defaults(**params_config)
-            except Exception as e:
-                print("Error in loading: {} using default parser settings".format(e))
-
-        # 2. Continue with loading in params.
-        params = Config.__parse_args__(args=args, parser=parser, strict=strict)
-
-        _config = self
-
-        # Splits params and add to config
-        Config.__split_params__(params=params, _config=_config)
-
-        # Make the is_set map
-        _config["__is_set"] = {}
-
-        # Reparse args using default of unset
-        parser_no_defaults = copy.deepcopy(parser)
-
-        # Only command as the arg, else no args
-        default_param_args = (
-            [_config.get("command")]
-            if _config.get("command") is not None and _config.get("subcommand") is None
-            else []
-        )
-        if _config.get("command") is not None and _config.get("subcommand") is not None:
-            default_param_args = [_config.get("command"), _config.get("subcommand")]
-
-        # Get all args by name
-        default_params = parser.parse_args(args=default_param_args)
-
-        all_default_args = default_params.__dict__.keys() | []
-        # Make a dict with keys as args and values as argparse.SUPPRESS
-        defaults_as_suppress = {key: argparse.SUPPRESS for key in all_default_args}
-        # Set the defaults to argparse.SUPPRESS, should remove them from the namespace
-        parser_no_defaults.set_defaults(**defaults_as_suppress)
-        parser_no_defaults._defaults.clear()  # Needed for quirk of argparse
-
-        # Check for subparsers and do the same
-        if parser_no_defaults._subparsers is not None:
-            for action in parser_no_defaults._subparsers._actions:
-                # Should only be the "command" subparser action
-                if isinstance(action, argparse._SubParsersAction):
-                    # Set the defaults to argparse.SUPPRESS, should remove them from the namespace
-                    # Each choice is the keyword for a command, we need to set the defaults for each of these
-                    # Note: we also need to clear the _defaults dict for each, this is a quirk of argparse
-                    cmd_parser: argparse.ArgumentParser
-                    for cmd_parser in action.choices.values():
-                        # If this choice is also a subparser, set defaults recursively
-                        if cmd_parser._subparsers:
-                            for action in cmd_parser._subparsers._actions:
-                                # Should only be the "command" subparser action
-                                if isinstance(action, argparse._SubParsersAction):
-                                    cmd_parser: argparse.ArgumentParser
-                                    for cmd_parser in action.choices.values():
-                                        cmd_parser.set_defaults(**defaults_as_suppress)
-                                        cmd_parser._defaults.clear()  # Needed for quirk of argparse
-                        else:
-                            cmd_parser.set_defaults(**defaults_as_suppress)
-                            cmd_parser._defaults.clear()  # Needed for quirk of argparse
-
-        # Reparse the args, but this time with the defaults as argparse.SUPPRESS
-        params_no_defaults = Config.__parse_args__(
-            args=args, parser=parser_no_defaults, strict=strict
-        )
-
-        # Diff the params and params_no_defaults to get the is_set map
-        _config["__is_set"] = {
-            arg_key: True
-            for arg_key in [
-                k
-                for k, _ in filter(
-                    lambda kv: kv[1] != argparse.SUPPRESS,
-                    params_no_defaults.__dict__.items(),
-                )
-            ]
-        }
-
-    @staticmethod
-    def __split_params__(params: argparse.Namespace, _config: "Config"):
-        # Splits params on dot syntax i.e neuron.axon_port and adds to _config
-        for arg_key, arg_val in params.__dict__.items():
-            split_keys = arg_key.split(".")
-            head = _config
-            keys = split_keys
-            while len(keys) > 1:
-                if (
-                    hasattr(head, keys[0]) and head[keys[0]] is not None
-                ):  # Needs to be Config
-                    head = getattr(head, keys[0])
-                    keys = keys[1:]
-                else:
-                    head[keys[0]] = Config()
-                    head = head[keys[0]]
-                    keys = keys[1:]
-            if len(keys) == 1:
-                head[keys[0]] = arg_val
-
-    @staticmethod
-    def __parse_args__(
-        args: List[str], parser: argparse.ArgumentParser = None, strict: bool = False
-    ) -> argparse.Namespace:
-        """Parses the passed args use the passed parser.
-
-        Args:
-            args (List[str]):
-                List of arguments to parse.
-            parser (argparse.ArgumentParser):
-                Command line parser object.
-            strict (bool):
-                If ``true``, the command line arguments are strictly parsed.
-        Returns:
-            Namespace:
-                Namespace object created from parser arguments.
-        """
-        if not strict:
-            params, unrecognized = parser.parse_known_args(args=args)
-            params_list = list(params.__dict__)
-            # bug within argparse itself, does not correctly set value for boolean flags
-            for unrec in unrecognized:
-                if unrec.startswith("--") and unrec[2:] in params_list:
-                    # Set the missing boolean value to true
-                    setattr(params, unrec[2:], True)
-        else:
-            params = parser.parse_args(args=args)
-
-        return params
-
-    def __deepcopy__(self, memo) -> "Config":
-        _default = self.__default__
-
-        config_state = self.__getstate__()
-        config_copy = Config()
-        memo[id(self)] = config_copy
-
-        config_copy.__setstate__(config_state)
-        config_copy.__default__ = _default
-
-        config_copy["__is_set"] = deepcopy(self["__is_set"], memo)
-
-        return config_copy
-
-    def __repr__(self) -> str:
-        return self.__str__()
-
-    @staticmethod
-    def _remove_private_keys(d):
-        if "__parser" in d:
-            d.pop("__parser", None)
-        if "__is_set" in d:
-            d.pop("__is_set", None)
-        for k, v in list(d.items()):
-            if isinstance(v, dict):
-                Config._remove_private_keys(v)
-        return d
-
-    def __str__(self) -> str:
-        # remove the parser and is_set map from the visible config
-        visible = copy.deepcopy(self.toDict())
-        visible.pop("__parser", None)
-        visible.pop("__is_set", None)
-        cleaned = Config._remove_private_keys(visible)
-        return "\n" + yaml.dump(cleaned, sort_keys=False)
-
-    def copy(self) -> "Config":
-        return copy.deepcopy(self)
-
-    def to_string(self, items) -> str:
-        """Get string from items"""
-        return "\n" + yaml.dump(items.toDict())
-
-    def update_with_kwargs(self, kwargs):
-        """Add config to self"""
-        for key, val in kwargs.items():
-            self[key] = val
-
-    @classmethod
-    def _merge(cls, a, b):
-        """Merge two configurations recursively.
-        If there is a conflict, the value from the second configuration will take precedence.
-        """
-        for key in b:
-            if key in a:
-                if isinstance(a[key], dict) and isinstance(b[key], dict):
-                    a[key] = cls._merge(a[key], b[key])
-                else:
-                    a[key] = b[key]
-            else:
-                a[key] = b[key]
-        return a
-
-    def merge(self, b):
-        """
-        Merges the current config with another config.
-
-        Args:
-            b: Another config to merge.
-        """
-        self._merge(self, b)
-
-    @classmethod
-    def merge_all(cls, configs: List["Config"]) -> "Config":
-        """
-        Merge all configs in the list into one config.
-        If there is a conflict, the value from the last configuration in the list will take precedence.
-
-        Args:
-            configs (list of config):
-                List of configs to be merged.
-
-        Returns:
-            config:
-                Merged config object.
-        """
-        result = cls()
-        for cfg in configs:
-            result.merge(cfg)
-        return result
-
-    def is_set(self, param_name: str) -> bool:
-        """
-        Returns a boolean indicating whether the parameter has been set or is still the default.
-        """
-        if param_name not in self.get("__is_set"):
-            return False
-        else:
-            return self.get("__is_set")[param_name]
-
-    def __check_for_missing_required_args(
-        self, parser: argparse.ArgumentParser, args: List[str]
-    ) -> List[str]:
-        required_args = self.__get_required_args_from_parser(parser)
-        missing_args = [arg for arg in required_args if not any(arg in s for s in args)]
-        return missing_args
-
-    @staticmethod
-    def __get_required_args_from_parser(parser: argparse.ArgumentParser) -> List[str]:
-        required_args = []
-        for action in parser._actions:
-            if action.required:
-                # Prefix the argument with '--' if it's a long argument, or '-' if it's short
-                prefix = "--" if len(action.dest) > 1 else "-"
-                required_args.append(prefix + action.dest)
-        return required_args
-
-
-T = TypeVar("T", bound="DefaultConfig")
-
-
-class DefaultConfig(Config):
-    """A Config with a set of default values."""
-
-    @classmethod
-    def default(cls: Type[T]) -> T:
-        """
-        Get default config.
-        """
-        raise NotImplementedError("Function default is not implemented.")
diff --git a/bittensor_wallet/errors.py b/bittensor_wallet/errors.py
deleted file mode 100644
index 01bd3f3..0000000
--- a/bittensor_wallet/errors.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# The MIT License (MIT)
-# Copyright © 2024 Opentensor Foundation
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
-# documentation files (the “Software”), to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
-
-
-class KeyFileError(Exception):
-    """Error thrown when the keyfile is corrupt, non-writable, non-readable or the password used to decrypt is invalid."""
diff --git a/bittensor_wallet/errors/__init__.py b/bittensor_wallet/errors/__init__.py
new file mode 100644
index 0000000..9bd501f
--- /dev/null
+++ b/bittensor_wallet/errors/__init__.py
@@ -0,0 +1,4 @@
+from bittensor_wallet.bittensor_wallet import errors as _
+
+ConfigurationError = _.ConfigurationError
+KeyFileError = _.KeyFileError
diff --git a/bittensor_wallet/keyfile.py b/bittensor_wallet/keyfile.py
deleted file mode 100644
index e68ede7..0000000
--- a/bittensor_wallet/keyfile.py
+++ /dev/null
@@ -1,703 +0,0 @@
-# The MIT License (MIT)
-# Copyright © 2024 Opentensor Foundation
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
-# documentation files (the “Software”), to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
-
-import base64
-import getpass
-import json
-import os
-import stat
-from pathlib import Path
-from typing import Optional
-
-from ansible.parsing.vault import AnsibleVaultError
-from ansible_vault import Vault
-from cryptography.exceptions import InvalidSignature, InvalidKey
-from cryptography.fernet import Fernet, InvalidToken
-from cryptography.hazmat.backends import default_backend
-from cryptography.hazmat.primitives import hashes
-from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
-from nacl import pwhash, secret
-from password_strength import PasswordPolicy
-from rich.console import Console
-from rich.prompt import Confirm
-from substrateinterface import Keypair
-from substrateinterface.utils.ss58 import ss58_encode
-from termcolor import colored
-
-from .errors import KeyFileError
-from .utils import SS58_FORMAT
-
-NACL_SALT = b"\x13q\x83\xdf\xf1Z\t\xbc\x9c\x90\xb5Q\x879\xe9\xb1"
-console = Console()
-
-
-def serialized_keypair_to_keyfile_data(keypair: "Keypair") -> bytes:
-    """Serializes keypair object into keyfile data.
-
-    Args:
-        keypair (Keypair): The keypair object to be serialized.
-    Returns:
-        data (bytes): Serialized keypair data.
-    """
-    json_data = {
-        "accountId": "0x" + keypair.public_key.hex() if keypair.public_key else None,
-        "publicKey": "0x" + keypair.public_key.hex() if keypair.public_key else None,
-        "privateKey": "0x" + keypair.private_key.hex() if keypair.private_key else None,
-        "secretPhrase": keypair.mnemonic if keypair.mnemonic else None,
-        "secretSeed": (
-            "0x"
-            + (
-                keypair.seed_hex
-                if isinstance(keypair.seed_hex, str)
-                else keypair.seed_hex.hex()
-            )
-            if keypair.seed_hex
-            else None
-        ),
-        "ss58Address": keypair.ss58_address if keypair.ss58_address else None,
-    }
-    data = json.dumps(json_data).encode()
-    return data
-
-
-def deserialize_keypair_from_keyfile_data(keyfile_data: bytes) -> "Keypair":
-    """Deserializes Keypair object from passed keyfile data.
-
-    Args:
-        keyfile_data (bytes): The keyfile data as bytes to be loaded.
-    Returns:
-        keypair (Keypair): The Keypair loaded from bytes.
-    Raises:
-        KeyFileError: Raised if the passed bytes cannot construct a keypair object.
-    """
-    keyfile_data_ = keyfile_data.decode()
-    try:
-        keyfile_dict = dict(json.loads(keyfile_data_))
-    except Exception:
-        string_value = str(keyfile_data_)
-        if string_value[:2] == "0x":
-            string_value = ss58_encode(string_value)
-            keyfile_dict = {
-                "accountId": None,
-                "publicKey": None,
-                "privateKey": None,
-                "secretPhrase": None,
-                "secretSeed": None,
-                "ss58Address": string_value,
-            }
-        else:
-            raise KeyFileError(
-                f"Keypair could not be created from keyfile data: {string_value}"
-            )
-
-    if "secretSeed" in keyfile_dict and keyfile_dict["secretSeed"] is not None:
-        return Keypair.create_from_seed(keyfile_dict["secretSeed"])
-
-    elif "secretPhrase" in keyfile_dict and keyfile_dict["secretPhrase"] is not None:
-        return Keypair.create_from_mnemonic(mnemonic=keyfile_dict["secretPhrase"])
-
-    elif keyfile_dict.get("privateKey", None) is not None:
-        # May have the above dict keys also, but we want to preserve the first two
-        return Keypair.create_from_private_key(
-            keyfile_dict["privateKey"], ss58_format=SS58_FORMAT
-        )
-
-    if "ss58Address" in keyfile_dict and keyfile_dict["ss58Address"] is not None:
-        return Keypair(ss58_address=keyfile_dict["ss58Address"])
-
-    else:
-        raise KeyFileError(
-            "Keypair could not be created from keyfile data: {}".format(keyfile_dict)
-        )
-
-
-def validate_password(password: str) -> bool:
-    """Validates the password against a password policy.
-
-    Args:
-        password (str): The password to verify.
-    Returns:
-        valid (bool): ``True`` if the password meets validity requirements.
-    """
-    policy = PasswordPolicy.from_names(strength=0.20, entropybits=10, length=6)
-    if not password:
-        return False
-    tested_pass = policy.password(password)
-    result = tested_pass.test()
-    if len(result) > 0:
-        print(
-            colored(
-                "Password not strong enough. Try increasing the length of the password or the password complexity"
-            )
-        )
-        return False
-    password_verification = getpass.getpass("Retype your password: ")
-    if password != password_verification:
-        print("Passwords do not match")
-        return False
-    return True
-
-
-def ask_password_to_encrypt() -> str:
-    """Prompts the user to enter a password for key encryption.
-
-    Returns:
-        password (str): The valid password entered by the user.
-    """
-    valid = False
-    while not valid:
-        password = getpass.getpass("Specify password for key encryption: ")
-        valid = validate_password(password)
-    return password
-
-
-def keyfile_data_is_encrypted_nacl(keyfile_data: bytes) -> bool:
-    """Returns true if the keyfile data is NaCl encrypted.
-
-    Args:
-        keyfile_data ( bytes, required ):
-            Bytes to validate.
-    Returns:
-        is_nacl (bool):
-            ``True`` if data is ansible encrypted.
-    """
-    return keyfile_data[: len("$NACL")] == b"$NACL"
-
-
-def keyfile_data_is_encrypted_ansible(keyfile_data: bytes) -> bool:
-    """Returns true if the keyfile data is ansible encrypted.
-
-    Args:
-        keyfile_data (bytes): The bytes to validate.
-    Returns:
-        is_ansible (bool): True if the data is ansible encrypted.
-    """
-    return keyfile_data[:14] == b"$ANSIBLE_VAULT"
-
-
-def keyfile_data_is_encrypted_legacy(keyfile_data: bytes) -> bool:
-    """Returns true if the keyfile data is legacy encrypted.
-    Args:
-        keyfile_data (bytes): The bytes to validate.
-    Returns:
-        is_legacy (bool): ``True`` if the data is legacy encrypted.
-    """
-    return keyfile_data[:6] == b"gAAAAA"
-
-
-def keyfile_data_is_encrypted(keyfile_data: bytes) -> bool:
-    """Returns ``true`` if the keyfile data is encrypted.
-
-    Args:
-        keyfile_data (bytes): The bytes to validate.
-    Returns:
-        is_encrypted (bool): ``True`` if the data is encrypted.
-    """
-    return (
-        keyfile_data_is_encrypted_nacl(keyfile_data)
-        or keyfile_data_is_encrypted_ansible(keyfile_data)
-        or keyfile_data_is_encrypted_legacy(keyfile_data)
-    )
-
-
-def keyfile_data_encryption_method(keyfile_data: bytes) -> str:
-    """Returns type of encryption method as a string.
-
-    Args:
-        keyfile_data (bytes, required): Bytes to validate
-    Returns:
-        encryption_method (str): returns the name of encryption method.
-    """
-
-    if keyfile_data_is_encrypted_nacl(keyfile_data):
-        return "NaCl"
-    elif keyfile_data_is_encrypted_ansible(keyfile_data):
-        return "Ansible Vault"
-    elif keyfile_data_is_encrypted_legacy(keyfile_data):
-        return "legacy"
-
-
-def legacy_encrypt_keyfile_data(
-    keyfile_data: bytes, password: Optional[str] = None
-) -> bytes:
-    password = ask_password_to_encrypt() if password is None else password
-    with console.status(
-        ":exclamation_mark: Encrypting key with legacy encryption method..."
-    ):
-        vault = Vault(password)
-    return vault.vault.encrypt(keyfile_data)
-
-
-def encrypt_keyfile_data(keyfile_data: bytes, password: Optional[str] = None) -> bytes:
-    """Encrypts the passed keyfile data using ansible vault.
-
-    Args:
-        keyfile_data (bytes): The bytes to encrypt.
-        password (str, optional): The password used to encrypt the data. If ``None``, asks for user input.
-    Returns:
-        encrypted_data (bytes): The encrypted data.
-    """
-    password = ask_password_to_encrypt() if password is None else password
-    password = bytes(password, "utf-8")
-    kdf = pwhash.argon2i.kdf
-    key = kdf(
-        secret.SecretBox.KEY_SIZE,
-        password,
-        NACL_SALT,
-        opslimit=pwhash.argon2i.OPSLIMIT_SENSITIVE,
-        memlimit=pwhash.argon2i.MEMLIMIT_SENSITIVE,
-    )
-    box = secret.SecretBox(key)
-    encrypted = box.encrypt(keyfile_data)
-    return b"$NACL" + encrypted
-
-
-def get_coldkey_password_from_environment(coldkey_name: str) -> Optional[str]:
-    """Retrieves the cold key password from the environment variables.
-
-    Args:
-        coldkey_name (str): The name of the cold key.
-    Returns:
-        password (str): The password retrieved from the environment variables, or ``None`` if not found.
-    """
-    envs = {
-        normalized_env_name: env_value
-        for env_name, env_value in os.environ.items()
-        if (normalized_env_name := env_name.upper()).startswith("BT_COLD_PW_")
-    }
-    return envs.get(f"BT_COLD_PW_{coldkey_name.replace('-', '_').upper()}")
-
-
-def decrypt_keyfile_data(
-    keyfile_data: bytes,
-    password: Optional[str] = None,
-    coldkey_name: Optional[str] = None,
-) -> bytes:
-    """Decrypts the passed keyfile data using ansible vault.
-
-    Args:
-        keyfile_data (bytes): The bytes to decrypt.
-        password (str, optional): The password used to decrypt the data. If ``None``, asks for user input.
-        coldkey_name (str, optional): The name of the cold key. If provided, retrieves the password from environment variables.
-
-    Returns:
-        decrypted_data (bytes): The decrypted data.
-
-    Raises:
-        KeyFileError: Raised if the file is corrupted or if the password is incorrect.
-    """
-    if coldkey_name is not None and password is None:
-        password = get_coldkey_password_from_environment(coldkey_name)
-
-    finished_password_input = False
-    while not finished_password_input:
-        try:
-            password_input: str = (
-                getpass.getpass("Enter password to unlock key: ")
-                if password is None
-                else password
-            )
-            with console.status(":key: Decrypting key..."):
-                # NaCl SecretBox decrypt.
-                if keyfile_data_is_encrypted_nacl(keyfile_data):
-                    password = bytes(password_input, "utf-8")
-                    kdf = pwhash.argon2i.kdf
-                    key = kdf(
-                        secret.SecretBox.KEY_SIZE,
-                        password,
-                        NACL_SALT,
-                        opslimit=pwhash.argon2i.OPSLIMIT_SENSITIVE,
-                        memlimit=pwhash.argon2i.MEMLIMIT_SENSITIVE,
-                    )
-                    box = secret.SecretBox(key)
-                    decrypted_keyfile_data = box.decrypt(keyfile_data[len("$NACL") :])
-                    finished_password_input = True
-
-                # Ansible decrypt.
-                elif keyfile_data_is_encrypted_ansible(keyfile_data):
-                    vault = Vault(password)
-                    decrypted_keyfile_data = vault.load(keyfile_data)
-                    finished_password_input = True
-
-                # Legacy decrypt.
-                elif keyfile_data_is_encrypted_legacy(keyfile_data):
-                    __SALT = b"Iguesscyborgslikemyselfhaveatendencytobeparanoidaboutourorigins"
-                    kdf = PBKDF2HMAC(
-                        algorithm=hashes.SHA256(),
-                        salt=__SALT,
-                        length=32,
-                        iterations=10000000,
-                        backend=default_backend(),
-                    )
-                    key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
-                    cipher_suite = Fernet(key)
-                    decrypted_keyfile_data = cipher_suite.decrypt(keyfile_data)
-                    finished_password_input = True
-                # Unknown.
-                else:
-                    raise KeyFileError(f"keyfile data: {str(keyfile_data)} is corrupt")
-
-        except (InvalidSignature, InvalidKey, InvalidToken, AnsibleVaultError):
-            console.print("Wrong password, try again")
-            password = None
-
-        except Exception as e:
-            if "Decryption failed. Ciphertext failed verification" in str(e):
-                console.print("Wrong password, try again")
-                password = None
-            else:
-                raise
-
-    if not isinstance(decrypted_keyfile_data, bytes):
-        decrypted_keyfile_data = json.dumps(decrypted_keyfile_data).encode()
-    return decrypted_keyfile_data
-
-
-class Keyfile:
-    """Defines an interface for a substrate interface keypair stored on device."""
-
-    def __init__(self, path: str):
-        self.path = os.path.expanduser(path)
-        self.name = Path(self.path).parent.stem
-
-    def __str__(self):
-        if not self.exists_on_device():
-            return "keyfile (empty, {})>".format(self.path)
-        if self.is_encrypted():
-            return "Keyfile ({} encrypted, {})>".format(
-                keyfile_data_encryption_method(self._read_keyfile_data_from_file()),
-                self.path,
-            )
-        else:
-            return "keyfile (decrypted, {})>".format(self.path)
-
-    def __repr__(self):
-        return self.__str__()
-
-    @property
-    def keypair(self) -> "Keypair":
-        """Returns the keypair from path, decrypts data if the file is encrypted.
-
-        Returns:
-            keypair (Keypair): The keypair stored under the path.
-        Raises:
-            KeyFileError: Raised if the file does not exist, is not readable, writable, corrupted, or if the password is incorrect.
-        """
-        return self.get_keypair()
-
-    @property
-    def data(self) -> bytes:
-        """Returns the keyfile data under path.
-
-        Returns:
-            keyfile_data (bytes): The keyfile data stored under the path.
-        Raises:
-            KeyFileError: Raised if the file does not exist, is not readable, or writable.
-        """
-        return self._read_keyfile_data_from_file()
-
-    @property
-    def keyfile_data(self) -> bytes:
-        """Returns the keyfile data under path.
-
-        Returns:
-            keyfile_data (bytes): The keyfile data stored under the path.
-        Raises:
-            KeyFileError: Raised if the file does not exist, is not readable, or writable.
-        """
-        return self._read_keyfile_data_from_file()
-
-    def set_keypair(
-        self,
-        keypair: "Keypair",
-        encrypt: bool = True,
-        overwrite: bool = False,
-        password: Optional[str] = None,
-    ):
-        """Writes the keypair to the file and optionally encrypts data.
-
-        Args:
-            keypair (Keypair): The keypair to store under the path.
-            encrypt (bool, optional): If ``True``, encrypts the file under the path. Default is ``True``.
-            overwrite (bool, optional): If ``True``, forces overwrite of the current file. Default is ``False``.
-            password (str, optional): The password used to encrypt the file. If ``None``, asks for user input.
-        Raises:
-            KeyFileError: Raised if the file does not exist, is not readable, writable, or if the password is incorrect.
-        """
-        self.make_dirs()
-        keyfile_data = serialized_keypair_to_keyfile_data(keypair)
-        if encrypt:
-            keyfile_data = encrypt_keyfile_data(keyfile_data, password)
-        self._write_keyfile_data_to_file(keyfile_data, overwrite=overwrite)
-
-    def get_keypair(self, password: Optional[str] = None) -> "Keypair":
-        """Returns the keypair from the path, decrypts data if the file is encrypted.
-
-        Args:
-            password (str, optional): The password used to decrypt the file. If ``None``, asks for user input.
-        Returns:
-            keypair (Keypair): The keypair stored under the path.
-        Raises:
-            KeyFileError: Raised if the file does not exist, is not readable, writable, corrupted, or if the password is incorrect.
-        """
-        keyfile_data = self._read_keyfile_data_from_file()
-        if keyfile_data_is_encrypted(keyfile_data):
-            decrypted_keyfile_data = decrypt_keyfile_data(
-                keyfile_data, password, coldkey_name=self.name
-            )
-        else:
-            decrypted_keyfile_data = keyfile_data
-        return deserialize_keypair_from_keyfile_data(decrypted_keyfile_data)
-
-    def make_dirs(self):
-        """Creates directories for the path if they do not exist."""
-        directory = os.path.dirname(self.path)
-        if not os.path.exists(directory):
-            os.makedirs(directory)
-
-    def exists_on_device(self) -> bool:
-        """Returns ``True`` if the file exists on the device.
-
-        Returns:
-            on_device (bool): ``True`` if the file is on the device.
-        """
-        if not os.path.isfile(self.path):
-            return False
-        return True
-
-    def is_readable(self) -> bool:
-        """Returns ``True`` if the file under path is readable.
-
-        Returns:
-            readable (bool): ``True`` if the file is readable.
-        """
-        if not self.exists_on_device():
-            return False
-        if not os.access(self.path, os.R_OK):
-            return False
-        return True
-
-    def is_writable(self) -> bool:
-        """Returns ``True`` if the file under path is writable.
-
-        Returns:
-            writable (bool): ``True`` if the file is writable.
-        """
-        if os.access(self.path, os.W_OK):
-            return True
-        return False
-
-    def is_encrypted(self) -> bool:
-        """Returns ``True`` if the file under path is encrypted.
-
-        Returns:
-            encrypted (bool): ``True`` if the file is encrypted.
-        """
-        if not self.exists_on_device():
-            return False
-        if not self.is_readable():
-            return False
-        return keyfile_data_is_encrypted(self._read_keyfile_data_from_file())
-
-    def _may_overwrite(self) -> bool:
-        """Asks the user if it is okay to overwrite the file.
-
-        Returns:
-            may_overwrite (bool): ``True`` if the user allows overwriting the file.
-        """
-        choice = input("File {} already exists. Overwrite? (y/N) ".format(self.path))
-        return choice == "y"
-
-    def check_and_update_encryption(
-        self, print_result: bool = True, no_prompt: bool = False
-    ):
-        """Check the version of keyfile and update if needed.
-
-        Args:
-            print_result (bool):
-                Print the checking result or not.
-            no_prompt (bool):
-                Skip if no prompt.
-        Raises:
-            KeyFileError:
-                Raised if the file does not exist, is not readable, writable.
-        Returns:
-            result (bool):
-                Return ``True`` if the keyfile is the most updated with nacl, else ``False``.
-        """
-        if not self.exists_on_device():
-            if print_result:
-                console.print(f"Keyfile does not exist. {self.path}")
-            return False
-        if not self.is_readable():
-            if print_result:
-                console.print(f"Keyfile is not redable. {self.path}")
-            return False
-        if not self.is_writable():
-            if print_result:
-                console.print(f"Keyfile is not writable. {self.path}")
-            return False
-
-        update_keyfile = False
-        if not no_prompt:
-            keyfile_data = self._read_keyfile_data_from_file()
-
-            # If the key is not nacl encrypted.
-            if keyfile_data_is_encrypted(
-                keyfile_data
-            ) and not keyfile_data_is_encrypted_nacl(keyfile_data):
-                terminate = False
-                console.print(
-                    f"You may update the keyfile to improve the security for storing your keys.\nWhile the key and the password stays the same, it would require providing your password once.\n:key:{self}\n"
-                )
-                update_keyfile = Confirm.ask("Update keyfile?")
-                if update_keyfile:
-                    stored_mnemonic = False
-                    while not stored_mnemonic:
-                        console.print(
-                            "\nPlease make sure you have the mnemonic stored in case an error occurs during the transfer.",
-                            style="white on red",
-                        )
-                        stored_mnemonic = Confirm.ask("Have you stored the mnemonic?")
-                        if not stored_mnemonic and not Confirm.ask(
-                            "You must proceed with a stored mnemonic, retry and continue this keyfile update?"
-                        ):
-                            terminate = True
-                            break
-
-                    decrypted_keyfile_data = None
-                    password = None
-                    while decrypted_keyfile_data is None and not terminate:
-                        try:
-                            password = getpass.getpass(
-                                "\nEnter password to update keyfile: "
-                            )
-                            decrypted_keyfile_data = decrypt_keyfile_data(
-                                keyfile_data, coldkey_name=self.name, password=password
-                            )
-                        except KeyFileError:
-                            if not Confirm.ask(
-                                "Invalid password, retry and continue this keyfile update?"
-                            ):
-                                terminate = True
-                                break
-
-                    if not terminate and password:
-                        encrypted_keyfile_data = encrypt_keyfile_data(
-                            decrypted_keyfile_data, password=password
-                        )
-                        self._write_keyfile_data_to_file(
-                            encrypted_keyfile_data, overwrite=True
-                        )
-
-        if print_result or update_keyfile:
-            keyfile_data = self._read_keyfile_data_from_file()
-            if not keyfile_data_is_encrypted(keyfile_data):
-                if print_result:
-                    console.print(f"\nKeyfile is not encrypted. \n:key: {self}")
-                return False
-            elif keyfile_data_is_encrypted_nacl(keyfile_data):
-                if print_result:
-                    console.print(
-                        f"\n:white_heavy_check_mark: Keyfile is updated. \n:key: {self}"
-                    )
-                return True
-            else:
-                if print_result:
-                    console.print(
-                        f'\n:cross_mark: Keyfile is outdated, please update with "btcli wallet update" \n:key: {self}'
-                    )
-                return False
-        return False
-
-    def encrypt(self, password: Optional[str] = None):
-        """Encrypts the file under the path.
-
-        Args:
-            password (str, optional): The password for encryption. If ``None``, asks for user input.
-        Raises:
-            KeyFileError: Raised if the file does not exist, is not readable, or writable.
-        """
-        if not self.exists_on_device():
-            raise KeyFileError("Keyfile at: {} does not exist".format(self.path))
-        if not self.is_readable():
-            raise KeyFileError("Keyfile at: {} is not readable".format(self.path))
-        if not self.is_writable():
-            raise KeyFileError("Keyfile at: {} is not writable".format(self.path))
-        keyfile_data = self._read_keyfile_data_from_file()
-        if not keyfile_data_is_encrypted(keyfile_data):
-            as_keypair = deserialize_keypair_from_keyfile_data(keyfile_data)
-            keyfile_data = serialized_keypair_to_keyfile_data(as_keypair)
-            keyfile_data = encrypt_keyfile_data(keyfile_data, password)
-        self._write_keyfile_data_to_file(keyfile_data, overwrite=True)
-
-    def decrypt(self, password: Optional[str] = None):
-        """Decrypts the file under the path.
-
-        Args:
-            password (str, optional): The password for decryption. If ``None``, asks for user input.
-        Raises:
-            KeyFileError: Raised if the file does not exist, is not readable, writable, corrupted, or if the password is incorrect.
-        """
-        if not self.exists_on_device():
-            raise KeyFileError("Keyfile at: {} does not exist".format(self.path))
-        if not self.is_readable():
-            raise KeyFileError("Keyfile at: {} is not readable".format(self.path))
-        if not self.is_writable():
-            raise KeyFileError("Keyfile at: {} is not writable".format(self.path))
-        keyfile_data = self._read_keyfile_data_from_file()
-        if keyfile_data_is_encrypted(keyfile_data):
-            keyfile_data = decrypt_keyfile_data(
-                keyfile_data, password, coldkey_name=self.name
-            )
-        as_keypair = deserialize_keypair_from_keyfile_data(keyfile_data)
-        keyfile_data = serialized_keypair_to_keyfile_data(as_keypair)
-        self._write_keyfile_data_to_file(keyfile_data, overwrite=True)
-
-    def _read_keyfile_data_from_file(self) -> bytes:
-        """Reads the keyfile data from the file.
-
-        Returns:
-            keyfile_data (bytes): The keyfile data stored under the path.
-        Raises:
-            KeyFileError: Raised if the file does not exist or is not readable.
-        """
-        if not self.exists_on_device():
-            raise KeyFileError("Keyfile at: {} does not exist".format(self.path))
-        if not self.is_readable():
-            raise KeyFileError("Keyfile at: {} is not readable".format(self.path))
-        with open(self.path, "rb") as file:
-            data = file.read()
-        return data
-
-    def _write_keyfile_data_to_file(self, keyfile_data: bytes, overwrite: bool = False):
-        """Writes the keyfile data to the file.
-
-        Args:
-            keyfile_data (bytes): The byte data to store under the path.
-            overwrite (bool, optional): If ``True``, overwrites the data without asking for permission from the user. Default is ``False``.
-        Raises:
-            KeyFileError: Raised if the file is not writable or the user responds No to the overwrite prompt.
-        """
-        # Check overwrite.
-        if self.exists_on_device() and not overwrite:
-            if not self._may_overwrite():
-                raise KeyFileError("Keyfile at: {} is not writable".format(self.path))
-        with open(self.path, "wb") as keyfile:
-            keyfile.write(keyfile_data)
-        # Set file permissions.
-        os.chmod(self.path, stat.S_IRUSR | stat.S_IWUSR)
diff --git a/bittensor_wallet/keyfile/__init__.py b/bittensor_wallet/keyfile/__init__.py
new file mode 100644
index 0000000..522284e
--- /dev/null
+++ b/bittensor_wallet/keyfile/__init__.py
@@ -0,0 +1,17 @@
+from bittensor_wallet.bittensor_wallet import keyfile as _
+
+serialized_keypair_to_keyfile_data = _.serialized_keypair_to_keyfile_data
+deserialize_keypair_from_keyfile_data = _.deserialize_keypair_from_keyfile_data
+validate_password = _.validate_password
+ask_password = _.ask_password
+ask_password_to_encrypt = ask_password  # backwards compatibility
+keyfile_data_is_encrypted_nacl = _.keyfile_data_is_encrypted_nacl
+keyfile_data_is_encrypted_ansible = _.keyfile_data_is_encrypted_ansible
+keyfile_data_is_encrypted_legacy = _.keyfile_data_is_encrypted_legacy
+keyfile_data_is_encrypted = _.keyfile_data_is_encrypted
+keyfile_data_encryption_method = _.keyfile_data_encryption_method
+legacy_encrypt_keyfile_data = _.legacy_encrypt_keyfile_data
+get_coldkey_password_from_environment = _.get_coldkey_password_from_environment
+encrypt_keyfile_data = _.encrypt_keyfile_data
+decrypt_keyfile_data = _.decrypt_keyfile_data
+Keyfile = _.Keyfile
diff --git a/bittensor_wallet/keypair/__init__.py b/bittensor_wallet/keypair/__init__.py
new file mode 100644
index 0000000..e715fe4
--- /dev/null
+++ b/bittensor_wallet/keypair/__init__.py
@@ -0,0 +1,3 @@
+from bittensor_wallet.bittensor_wallet import keypair as _
+
+Keypair = _.Keypair
diff --git a/bittensor_wallet/mock/keyfile_mock.py b/bittensor_wallet/mock/keyfile_mock.py
index 29126d4..153ff1e 100644
--- a/bittensor_wallet/mock/keyfile_mock.py
+++ b/bittensor_wallet/mock/keyfile_mock.py
@@ -17,9 +17,7 @@
 
 from typing import Optional
 
-from substrateinterface import Keypair
-
-from bittensor_wallet.keyfile import serialized_keypair_to_keyfile_data, Keyfile
+from bittensor_wallet import keyfile, Keypair, Keyfile
 
 
 class MockKeyfile(Keyfile):
@@ -31,7 +29,7 @@ def __init__(self, path: str):
         self._mock_keypair = Keypair.create_from_mnemonic(
             mnemonic="arrive produce someone view end scout bargain coil slight festival excess struggle"
         )
-        self._mock_data = serialized_keypair_to_keyfile_data(self._mock_keypair)
+        self._mock_data = keyfile.serialized_keypair_to_keyfile_data(self._mock_keypair)
 
     def __str__(self):
         if not self.exists_on_device():
@@ -64,7 +62,7 @@ def set_keypair(
         password: Optional[str] = None,
     ):
         self._mock_keypair = keypair
-        self._mock_data = serialized_keypair_to_keyfile_data(self._mock_keypair)
+        self._mock_data = keyfile.serialized_keypair_to_keyfile_data(self._mock_keypair)
 
     def get_keypair(self, password: Optional[str] = None) -> "Keypair":
         return self._mock_keypair
diff --git a/bittensor_wallet/mock/wallet_mock.py b/bittensor_wallet/mock/wallet_mock.py
index 9d6a1f4..55851a2 100644
--- a/bittensor_wallet/mock/wallet_mock.py
+++ b/bittensor_wallet/mock/wallet_mock.py
@@ -19,12 +19,9 @@
 from typing import Optional
 
 from Crypto.Hash import keccak
-from substrateinterface import Keypair
 
-from bittensor_wallet.utils import SS58_FORMAT
+from bittensor_wallet import Keyfile, Wallet, Keypair
 from .keyfile_mock import MockKeyfile
-from ..keyfile import Keyfile
-from ..wallet import Wallet
 
 
 class MockWallet(Wallet):
@@ -32,17 +29,24 @@ class MockWallet(Wallet):
     Mocked Version of the bittensor wallet class, meant to be used for testing
     """
 
-    def __init__(self, **kwargs):
+    def __init__(self, *args, **kwargs):
+        pass
+
+    def __new__(cls, name=None, hotkey=None, path=None, config=None, *args, **kwargs):
         r"""Init bittensor wallet object containing a hot and coldkey.
         Args:
             _mock (required=True, default=False):
                 If true creates a mock wallet with random keys.
         """
-        super().__init__(**kwargs)
+        cls = super().__new__(
+            cls, name=name, hotkey=hotkey, path=path, config=config, *args, **kwargs
+        )
         # For mocking.
-        self._is_mock = True
-        self._mocked_coldkey_keyfile = None
-        self._mocked_hotkey_keyfile = None
+        cls._is_mock = True
+        cls._mocked_coldkey_keyfile = None
+        cls._mocked_hotkey_keyfile = None
+
+        return cls
 
     @property
     def hotkey_file(self) -> "Keyfile":
@@ -110,7 +114,6 @@ def get_mock_keypair(uid: int, test_name: Optional[str] = None) -> Keypair:
 
     return Keypair.create_from_seed(
         seed_hex=int.to_bytes(uid, 32, "big", signed=False),
-        ss58_format=SS58_FORMAT,
     )
 
 
diff --git a/bittensor_wallet/utils.py b/bittensor_wallet/utils.py
deleted file mode 100644
index 9f5fe82..0000000
--- a/bittensor_wallet/utils.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# The MIT License (MIT)
-# Copyright © 2024 Opentensor Foundation
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
-# documentation files (the “Software”), to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
-
-from typing import Union
-
-from substrateinterface import Keypair as Keypair
-from substrateinterface.utils import ss58
-
-# Substrate ss58_format
-SS58_FORMAT = 42
-
-
-def get_ss58_format(ss58_address: str) -> int:
-    """Returns the ss58 format of the given ss58 address."""
-    return ss58.get_ss58_format(ss58_address)
-
-
-def is_valid_ss58_address(address: str) -> bool:
-    """
-    Checks if the given address is a valid ss58 address.
-
-    Args:
-        address(str): The address to check.
-
-    Returns:
-        True if the address is a valid ss58 address for Bittensor, False otherwise.
-    """
-    try:
-        return ss58.is_valid_ss58_address(
-            address, valid_ss58_format=SS58_FORMAT
-        ) or ss58.is_valid_ss58_address(
-            address, valid_ss58_format=42
-        )  # Default substrate ss58 format (legacy)
-    except IndexError:
-        return False
-
-
-def is_valid_ed25519_pubkey(public_key: Union[str, bytes]) -> bool:
-    """
-    Checks if the given public_key is a valid ed25519 key.
-
-    Args:
-        public_key(Union[str, bytes]): The public_key to check.
-
-    Returns:
-        True if the public_key is a valid ed25519 key, False otherwise.
-
-    """
-    try:
-        if isinstance(public_key, str):
-            if len(public_key) != 64 and len(public_key) != 66:
-                raise ValueError("a public_key should be 64 or 66 characters")
-        elif isinstance(public_key, bytes):
-            if len(public_key) != 32:
-                raise ValueError("a public_key should be 32 bytes")
-        else:
-            raise ValueError("public_key must be a string or bytes")
-
-        keypair = Keypair(public_key=public_key, ss58_format=SS58_FORMAT)
-
-        ss58_addr = keypair.ss58_address
-        return ss58_addr is not None
-
-    except (ValueError, IndexError):
-        return False
-
-
-def is_valid_bittensor_address_or_public_key(address: Union[str, bytes]) -> bool:
-    """
-    Checks if the given address is a valid destination address.
-
-    Args:
-        address(Union[str, bytes]): The address to check.
-
-    Returns:
-        True if the address is a valid destination address, False otherwise.
-    """
-    if isinstance(address, str):
-        # Check if ed25519
-        if address.startswith("0x"):
-            return is_valid_ed25519_pubkey(address)
-        else:
-            # Assume ss58 address
-            return is_valid_ss58_address(address)
-    elif isinstance(address, bytes):
-        # Check if ed25519
-        return is_valid_ed25519_pubkey(address)
-    else:
-        # Invalid address type
-        return False
diff --git a/bittensor_wallet/utils/__init__.py b/bittensor_wallet/utils/__init__.py
new file mode 100644
index 0000000..6f570d2
--- /dev/null
+++ b/bittensor_wallet/utils/__init__.py
@@ -0,0 +1,7 @@
+from bittensor_wallet.bittensor_wallet import utils as _
+
+get_ss58_format = _.get_ss58_format
+is_valid_ss58_address = _.is_valid_ss58_address
+is_valid_ed25519_pubkey = _.is_valid_ed25519_pubkey
+is_valid_bittensor_address_or_public_key = _.is_valid_bittensor_address_or_public_key
+SS58_FORMAT = _.SS58_FORMAT
diff --git a/bittensor_wallet/wallet.py b/bittensor_wallet/wallet.py
deleted file mode 100644
index 61ebf75..0000000
--- a/bittensor_wallet/wallet.py
+++ /dev/null
@@ -1,903 +0,0 @@
-# The MIT License (MIT)
-# Copyright © 2024 Opentensor Foundation
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
-# documentation files (the “Software”), to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
-
-"""Implementation of the wallet class, which manages balances with staking and transfer. Also manages hotkey and coldkey."""
-
-import argparse
-import copy
-import os
-from typing import Dict, Optional, Tuple, Union, overload
-
-from substrateinterface import Keypair
-from termcolor import colored
-
-from .config import Config
-from .errors import KeyFileError
-from .keyfile import Keyfile
-from .utils import (
-    is_valid_bittensor_address_or_public_key,
-    get_ss58_format,
-    SS58_FORMAT,
-)
-
-BT_WALLET_NAME = "default"
-BT_WALLET_PATH = "~/.bittensor/wallets/"
-
-
-def display_mnemonic_msg(keypair: Keypair, key_type: str):
-    """
-    Display the mnemonic and a warning message to keep the mnemonic safe.
-
-    Args:
-        keypair (Keypair): Keypair object.
-        key_type (str): Type of the key (coldkey or hotkey).
-    """
-    mnemonic = keypair.mnemonic
-    mnemonic_green = colored(mnemonic, "green")
-    print(
-        colored(
-            "\nIMPORTANT: Store this mnemonic in a secure (preferable offline place), as anyone "
-            "who has possession of this mnemonic can use it to regenerate the key and access your tokens.\n",
-            "red",
-        )
-    )
-    print("The mnemonic to the new {} is:\n\n{}\n".format(key_type, mnemonic_green))
-    print(
-        "You can use the mnemonic to recreate the key in case it gets lost. The command to use to regenerate the key using this mnemonic is:"
-    )
-    print('btcli w regen-{} --mnemonic "{}"'.format(key_type, mnemonic))
-    print("")
-
-
-class Wallet:
-    """
-    The wallet class in the Bittensor framework handles wallet functionality, crucial for participating in the Bittensor network.
-
-    It manages two types of keys: coldkey and hotkey, each serving different purposes in network operations. Each wallet contains a coldkey and a hotkey.
-
-    The coldkey is the user's primary key for holding stake in their wallet and is the only way that users
-    can access Tao. Coldkeys can hold tokens and should be encrypted on your device.
-
-    The coldkey is the primary key used for securing the wallet's stake in the Bittensor network (Tao) and
-    is critical for financial transactions like staking and unstaking tokens. It's recommended to keep the
-    coldkey encrypted and secure, as it holds the actual tokens.
-
-    The hotkey, in contrast, is used for operational tasks like subscribing to and setting weights in the
-    network. It's linked to the coldkey through the metagraph and does not directly hold tokens, thereby
-    offering a safer way to interact with the network during regular operations.
-
-    Args:
-        name (str): The name of the wallet, used to identify it among possibly multiple wallets.
-        hotkey (str): String identifier for the hotkey.
-        path (str): File system path where wallet keys are stored.
-        config (Config): Bittensor configuration object.
-        _hotkey, _coldkey, _coldkeypub (Keypair): Internal representations of the hotkey and coldkey.
-
-    Methods:
-        create_if_non_existent, create, recreate: Methods to handle the creation of wallet keys.
-        get_coldkey, get_hotkey, get_coldkeypub: Methods to retrieve specific keys.
-        set_coldkey, set_hotkey, set_coldkeypub: Methods to set or update keys.
-        hotkey_file, coldkey_file, coldkeypub_file: Properties that return respective key file objects.
-        regenerate_coldkey, regenerate_hotkey, regenerate_coldkeypub: Methods to regenerate keys from different sources.
-        Config, help, add_args: Utility methods for configuration and assistance.
-
-    The wallet class is a fundamental component for users to interact securely with the Bittensor network, facilitating both operational tasks and transactions involving value transfer across the network.
-
-    Example Usage::
-
-        # Create a new wallet with default coldkey and hotkey names
-        my_wallet = wallet()
-
-        # Access hotkey and coldkey
-        hotkey = my_wallet.get_hotkey()
-        coldkey = my_wallet.get_coldkey()
-
-        # Set a new coldkey
-        my_wallet.new_coldkey(n_words=24) # number of seed words to use
-
-        # Update wallet hotkey
-        my_wallet.set_hotkey(new_hotkey)
-
-        # Print wallet details
-        print(my_wallet)
-
-        # Access coldkey property, must use password to unlock
-        my_wallet.coldkey
-    """
-
-    def __init__(
-        self,
-        name: Optional[str] = None,
-        hotkey: Optional[str] = None,
-        path: Optional[str] = None,
-        config: Optional["Config"] = None,
-    ):
-        """
-        Initialize the bittensor wallet object containing a hot and coldkey.
-
-        Args:
-            name (str, optional): The name of the wallet to unlock for running bittensor. Defaults to ``default``.
-            hotkey (str, optional): The name of hotkey used to running the miner. Defaults to ``default``.
-            path (str, optional): The path to your bittensor wallets. Defaults to ``~/.bittensor/wallets/``.
-            config (Config, optional): config.Config(). Defaults to ``None``.
-        """
-        if config is None:
-            config = Wallet.config()
-
-        self.config = copy.deepcopy(config)
-        self.config.wallet.name = name or self.config.wallet.get(
-            "name", Wallet.config().name
-        )
-        self.config.wallet.hotkey = hotkey or self.config.wallet.get(
-            "hotkey", Wallet.config().hotkey
-        )
-        self.config.wallet.path = path or self.config.wallet.get(
-            "path", Wallet.config().path
-        )
-        self.config.wallet.path = self.config.wallet.path.strip("'")
-
-        self.name = self.config.wallet.name
-        self.path = self.config.wallet.path
-        self.hotkey_str = self.config.wallet.hotkey
-
-        self._hotkey = None
-        self._coldkey = None
-        self._coldkeypub = None
-
-    def __str__(self):
-        """
-        Returns a human-readable string representation of the wallet object.
-
-        Returns:
-            str: The string representation.
-        """
-        return f"Wallet (Name: '{self.name}', Hotkey: '{self.hotkey_str}', Path: '{self.path}')"
-
-    def __repr__(self):
-        """
-        Returns the string representation of the wallet object.
-
-        Returns:
-            str: The string representation.
-        """
-        return f"name: '{self.name}', hotkey: '{self.hotkey_str}', path: '{self.path}'"
-
-    @classmethod
-    def config(cls) -> "Config":
-        """
-        Get config from the argument parser.
-
-        Returns:
-            Config: Config object.
-        """
-        parser = argparse.ArgumentParser()
-        cls.add_args(parser)
-        return Config(parser, args=[])
-
-    @classmethod
-    def help(cls):
-        """
-        Print help to stdout.
-        """
-        parser = argparse.ArgumentParser()
-        cls.add_args(parser)
-        print(cls.__new__.__doc__)
-        parser.print_help()
-
-    @classmethod
-    def add_args(cls, parser: argparse.ArgumentParser, prefix: Optional[str] = None):
-        """
-        Accept specific arguments from parser.
-
-        Args:
-            parser (argparse.ArgumentParser): Argument parser object.
-            prefix (str): Argument prefix.
-        """
-        prefix_str = "" if prefix is None else prefix + "."
-        try:
-            default_name = os.getenv("BT_WALLET_NAME") or BT_WALLET_NAME
-            default_hotkey = os.getenv("BT_WALLET_NAME") or BT_WALLET_NAME
-            default_path = os.getenv("BT_WALLET_PATH") or BT_WALLET_PATH
-            parser.add_argument(
-                "--" + prefix_str + "wallet.name",
-                required=False,
-                default=default_name,
-                help="The name of the wallet to unlock for running bittensor "
-                "(name mock is reserved for mocking this wallet)",
-            )
-            parser.add_argument(
-                "--" + prefix_str + "wallet.hotkey",
-                required=False,
-                default=default_hotkey,
-                help="The name of the wallet's hotkey.",
-            )
-            parser.add_argument(
-                "--" + prefix_str + "wallet.path",
-                required=False,
-                default=default_path,
-                help="The path to your bittensor wallets",
-            )
-        except argparse.ArgumentError:
-            pass
-
-    def create_if_non_existent(
-        self, coldkey_use_password: bool = True, hotkey_use_password: bool = False
-    ) -> "Wallet":
-        """
-        Checks for existing coldkeypub and hotkeys, and creates them if non-existent.
-
-        Args:
-            coldkey_use_password (bool, optional): Whether to use a password for coldkey. Defaults to ``True``.
-            hotkey_use_password (bool, optional): Whether to use a password for hotkey. Defaults to ``False``.
-
-        Returns:
-            wallet: The wallet object.
-        """
-        return self.create(coldkey_use_password, hotkey_use_password)
-
-    def create(
-        self, coldkey_use_password: bool = True, hotkey_use_password: bool = False
-    ) -> "Wallet":
-        """
-        Checks for existing coldkeypub and hotkeys, and creates them if non-existent.
-
-        Args:
-            coldkey_use_password (bool, optional): Whether to use a password for coldkey. Defaults to ``True``.
-            hotkey_use_password (bool, optional): Whether to use a password for hotkey. Defaults to ``False``.
-
-        Returns:
-            wallet: The wallet object.
-        """
-        # ---- Setup Wallet. ----
-        if (
-            not self.coldkey_file.exists_on_device()
-            and not self.coldkeypub_file.exists_on_device()
-        ):
-            self.create_new_coldkey(n_words=12, use_password=coldkey_use_password)
-        else:
-            print(f"ColdKey for the wallet '{self.name}' already exist.")
-        if not self.hotkey_file.exists_on_device():
-            self.create_new_hotkey(n_words=12, use_password=hotkey_use_password)
-        else:
-            print(f"HotKey for the wallet '{self.name}' already exist.")
-        return self
-
-    def recreate(
-        self, coldkey_use_password: bool = True, hotkey_use_password: bool = False
-    ) -> "Wallet":
-        """
-        Checks for existing coldkeypub and hotkeys and creates them if non-existent.
-
-        Args:
-            coldkey_use_password (bool, optional): Whether to use a password for coldkey. Defaults to ``True``.
-            hotkey_use_password (bool, optional): Whether to use a password for hotkey. Defaults to ``False``.
-
-        Returns:
-            wallet: The wallet object.
-        """
-        # ---- Setup Wallet. ----
-        self.create_new_coldkey(n_words=12, use_password=coldkey_use_password)
-        self.create_new_hotkey(n_words=12, use_password=hotkey_use_password)
-        return self
-
-    @property
-    def hotkey_file(self) -> "Keyfile":
-        """
-        Property that returns the hotkey file.
-
-        Returns:
-            Keyfile: The hotkey file.
-        """
-        wallet_path = os.path.expanduser(os.path.join(self.path, self.name))
-        hotkey_path = os.path.join(wallet_path, "hotkeys", self.hotkey_str)
-        return Keyfile(path=hotkey_path)
-
-    @property
-    def coldkey_file(self) -> "Keyfile":
-        """
-        Property that returns the coldkey file.
-
-        Returns:
-            Keyfile: The coldkey file.
-        """
-        wallet_path = os.path.expanduser(os.path.join(self.path, self.name))
-        coldkey_path = os.path.join(wallet_path, "coldkey")
-        return Keyfile(path=coldkey_path)
-
-    @property
-    def coldkeypub_file(self) -> "Keyfile":
-        """
-        Property that returns the coldkeypub file.
-
-        Returns:
-            Keyfile: The coldkeypub file.
-        """
-        wallet_path = os.path.expanduser(os.path.join(self.path, self.name))
-        coldkeypub_path = os.path.join(wallet_path, "coldkeypub.txt")
-        return Keyfile(path=coldkeypub_path)
-
-    def set_hotkey(
-        self, keypair: "Keypair", encrypt: bool = False, overwrite: bool = False
-    ):
-        """
-        Sets the hotkey for the wallet.
-
-        Args:
-            keypair (Keypair): The hotkey keypair.
-            encrypt (bool, optional): Whether to encrypt the hotkey. Defaults to ``False``.
-            overwrite (bool, optional): Whether to overwrite an existing hotkey. Defaults to ``False``.
-        """
-        self._hotkey = keypair
-        self.hotkey_file.set_keypair(keypair, encrypt=encrypt, overwrite=overwrite)
-
-    def set_coldkeypub(
-        self, keypair: "Keypair", encrypt: bool = False, overwrite: bool = False
-    ):
-        """
-        Sets the coldkeypub for the wallet.
-
-        Args:
-            keypair (Keypair): The coldkeypub keypair.
-            encrypt (bool, optional): Whether to encrypt the coldkeypub. Defaults to ``False``.
-            overwrite (bool, optional): Whether to overwrite an existing coldkeypub. Defaults to ``False``.
-
-        Returns:
-            Keyfile: The coldkeypub file.
-        """
-        self._coldkeypub = Keypair(ss58_address=keypair.ss58_address)
-        self.coldkeypub_file.set_keypair(
-            self._coldkeypub, encrypt=encrypt, overwrite=overwrite
-        )
-        return self.coldkeypub_file
-
-    def set_coldkey(
-        self,
-        keypair: "Keypair",
-        encrypt: bool = True,
-        overwrite: bool = False,
-    ) -> "Keyfile":
-        """
-        Sets the coldkey for the wallet.
-
-        Args:
-            keypair (Keypair): The coldkey keypair.
-            encrypt (bool, optional): Whether to encrypt the coldkey. Defaults to ``True``.
-            overwrite (bool, optional): Whether to overwrite an existing coldkey. Defaults to ``False``.
-
-            Returns:
-        Keyfile: The coldkey file.
-        """
-        self._coldkey = keypair
-        self.coldkey_file.set_keypair(
-            self._coldkey, encrypt=encrypt, overwrite=overwrite
-        )
-        return self.coldkey_file
-
-    def get_coldkey(self, password: Optional[str] = None) -> "Keypair":
-        """
-        Gets the coldkey from the wallet.
-
-        Args:
-            password (str, optional): The password to decrypt the coldkey. Defaults to ``None``.
-
-        Returns:
-            Keypair: The coldkey keypair.
-        """
-        return self.coldkey_file.get_keypair(password=password)
-
-    def get_hotkey(self, password: Optional[str] = None) -> "Keypair":
-        """
-        Gets the hotkey from the wallet.
-
-        Args:
-            password (str, optional): The password to decrypt the hotkey. Defaults to ``None``.
-
-        Returns:
-            Keypair: The hotkey keypair.
-        """
-        return self.hotkey_file.get_keypair(password=password)
-
-    def get_coldkeypub(self, password: Optional[str] = None) -> "Keypair":
-        """
-        Gets the coldkeypub from the wallet.
-
-        Args:
-            password (str, optional): The password to decrypt the coldkeypub. Defaults to ``None``.
-
-        Returns:
-            Keypair: The coldkeypub keypair.
-        """
-        return self.coldkeypub_file.get_keypair(password=password)
-
-    @property
-    def hotkey(self) -> "Keypair":
-        """Loads the hotkey from wallet.path/wallet.name/hotkeys/wallet.hotkey or raises an error.
-
-        Returns:
-            hotkey (Keypair):
-                hotkey loaded from Config arguments.
-
-        Raises:
-            KeyFileError: Raised if the file is corrupt of non-existent.
-            CryptoKeyError: Raised if the user enters an incorrect password for an encrypted keyfile.
-        """
-        if self._hotkey is None:
-            try:
-                self._hotkey = self.hotkey_file.keypair
-            except KeyFileError as error:
-                print(f"KeyFileError: {error.args[0] if error.args else str(error)}.")
-                raise
-        return self._hotkey
-
-    @property
-    def coldkey(self) -> "Keypair":
-        """Loads the coldkey from wallet.path/wallet.name/coldkey or raises an error.
-
-        Returns:
-            coldkey (Keypair): coldkey loaded from Config arguments.
-
-        Raises:
-            KeyFileError: Raised if the file is corrupt of non-existent.
-            CryptoKeyError: Raised if the user enters an incorrect password for an encrypted keyfile.
-        """
-        if self._coldkey is None:
-            try:
-                self._coldkey = self.coldkey_file.keypair
-            except Exception as error:
-                print(f"Error: {error.args[0] if error.args else str(error)}.")
-                raise KeyFileError
-
-        return self._coldkey
-
-    @property
-    def coldkeypub(self) -> "Keypair":
-        """Loads the coldkeypub from wallet.path/wallet.name/coldkeypub.txt or raises an error.
-
-        Returns:
-            coldkeypub (Keypair): coldkeypub loaded from Config arguments.
-
-        Raises:
-            KeyFileError: Raised if the file is corrupt of non-existent.
-            CryptoKeyError: Raised if the user enters an incorrect password for an encrypted keyfile.
-        """
-        if self._coldkeypub is None:
-            try:
-                self._coldkeypub = self.coldkeypub_file.keypair
-            except KeyFileError as error:
-                print(f"KeyFileError: {error.args[0] if error.args else str(error)}.")
-                raise
-        return self._coldkeypub
-
-    def create_coldkey_from_uri(
-        self,
-        uri: str,
-        use_password: bool = True,
-        overwrite: bool = False,
-        suppress: bool = False,
-    ) -> "Wallet":
-        """Creates coldkey from uri string, optionally encrypts it with the user-provided password.
-
-        Args:
-            uri: (str, required): URI string to use i.e., ``/Alice`` or ``/Bob``.
-            use_password (bool, optional): Is the created key password protected.
-            overwrite (bool, optional): Determines if this operation overwrites the coldkey under the same path ``<wallet path>/<wallet name>/coldkey``.
-            suppress (bool, optional): If ``True``, suppresses the display of the mnemonic message. Defaults to ``False``.
-
-        Returns:
-            wallet (Wallet): This object with newly created coldkey.
-        """
-        keypair = Keypair.create_from_uri(uri)
-        if not suppress:
-            display_mnemonic_msg(keypair, "coldkey")
-        self.set_coldkey(keypair, encrypt=use_password, overwrite=overwrite)
-        self.set_coldkeypub(keypair, overwrite=overwrite)
-        return self
-
-    def create_hotkey_from_uri(
-        self,
-        uri: str,
-        use_password: bool = False,
-        overwrite: bool = False,
-        suppress: bool = False,
-    ) -> "Wallet":
-        """Creates hotkey from uri string, optionally encrypts it with the user-provided password.
-
-        Args:
-            uri: (str, required): URI string to use i.e., ``/Alice`` or ``/Bob``
-            use_password (bool, optional): Is the created key password protected.
-            overwrite (bool, optional): Determines if this operation overwrites the hotkey under the same path ``<wallet path>/<wallet name>/hotkeys/<hotkey>``.
-            suppress (bool, optional): If ``True``, suppresses the display of the mnemonic message. Defaults to ``False``.
-
-        Returns:
-            wallet (Wallet): This object with newly created hotkey.
-        """
-        keypair = Keypair.create_from_uri(uri)
-        if not suppress:
-            display_mnemonic_msg(keypair, "hotkey")
-        self.set_hotkey(keypair, encrypt=use_password, overwrite=overwrite)
-        return self
-
-    def unlock_coldkey(self) -> Keypair:
-        """
-        Unlocks the coldkey (prompts password if locked)
-
-        Returns:
-            coldkey (Keypair): the unlocked coldkey Keypair.
-        """
-        return self.coldkey
-
-    def unlock_coldkeypub(self) -> Keypair:
-        """
-        Unlocks the coldkeypub.
-
-        Returns:
-            coldkeypub (Keypair): the unlocked coldkeypub Keypair.
-        """
-        return self.coldkeypub
-
-    def unlock_hotkey(self) -> Keypair:
-        """
-        Unlocks the hotkey.
-
-        Returns:
-            hotkey (Keypair): the unlocked hotkey Keypair.
-        """
-        return self.hotkey
-
-    def new_coldkey(
-        self,
-        n_words: int = 12,
-        use_password: bool = True,
-        overwrite: bool = False,
-        suppress: bool = False,
-    ) -> "Wallet":
-        """Creates a new coldkey, optionally encrypts it with the user-provided password and saves to disk.
-
-        Args:
-            n_words: (int, optional): Number of mnemonic words to use.
-            use_password (bool, optional): Is the created key password protected.
-            overwrite (bool, optional): Determines if this operation overwrites the coldkey under the same path ``<wallet path>/<wallet name>/coldkey``.
-            suppress (bool, optional): If ``True``, suppresses the display of the mnemonic message. Defaults to ``False``.
-
-        Returns:
-            wallet (Wallet): This object with newly created coldkey.
-        """
-        return self.create_new_coldkey(n_words, use_password, overwrite, suppress)
-
-    def create_new_coldkey(
-        self,
-        n_words: int = 12,
-        use_password: bool = True,
-        overwrite: bool = False,
-        suppress: bool = False,
-    ) -> "Wallet":
-        """Creates a new coldkey, optionally encrypts it with the user-provided password and saves to disk.
-
-        Args:
-            n_words: (int, optional): Number of mnemonic words to use.
-            use_password (bool, optional): Is the created key password protected.
-            overwrite (bool, optional): Determines if this operation overwrites the coldkey under the same path ``<wallet path>/<wallet name>/coldkey``.
-            suppress (bool, optional): If ``True``, suppresses the display of the mnemonic message. Defaults to ``False``.
-
-        Returns:
-            wallet (Wallet): This object with newly created coldkey.
-        """
-        mnemonic = Keypair.generate_mnemonic(n_words)
-        keypair = Keypair.create_from_mnemonic(mnemonic)
-        if not suppress:
-            display_mnemonic_msg(keypair, "coldkey")
-        self.set_coldkey(keypair, encrypt=use_password, overwrite=overwrite)
-        self.set_coldkeypub(keypair, overwrite=overwrite)
-        return self
-
-    def new_hotkey(
-        self,
-        n_words: int = 12,
-        use_password: bool = False,
-        overwrite: bool = False,
-        suppress: bool = False,
-    ) -> "Wallet":
-        """Creates a new hotkey, optionally encrypts it with the user-provided password and saves to disk.
-
-        Args:
-            n_words: (int, optional): Number of mnemonic words to use.
-            use_password (bool, optional): Is the created key password protected.
-            overwrite (bool, optional): Determines if this operation overwrites the hotkey under the same path ``<wallet path>/<wallet name>/hotkeys/<hotkey>``.
-            suppress (bool, optional): If ``True``, suppresses the display of the mnemonic message. Defaults to ``False``.
-
-        Returns:
-            wallet (Wallet):
-                This object with newly created hotkey.
-        """
-        return self.create_new_hotkey(n_words, use_password, overwrite, suppress)
-
-    def create_new_hotkey(
-        self,
-        n_words: int = 12,
-        use_password: bool = False,
-        overwrite: bool = False,
-        suppress: bool = False,
-    ) -> "Wallet":
-        """Creates a new hotkey, optionally encrypts it with the user-provided password and saves to disk.
-
-        Args:
-            n_words: (int, optional): Number of mnemonic words to use.
-            use_password (bool, optional): Is the created key password protected.
-            overwrite (bool, optional): Will this operation overwrite the hotkey under the same path <wallet path>/<wallet name>/hotkeys/<hotkey>
-            suppress (bool, optional): If ``True``, suppresses the display of the mnemonic message. Defaults to ``False``.
-
-        Returns:
-            wallet (Wallet):
-                This object with newly created hotkey.
-        """
-        mnemonic = Keypair.generate_mnemonic(n_words)
-        keypair = Keypair.create_from_mnemonic(mnemonic)
-
-        if not suppress:
-            display_mnemonic_msg(keypair, "hotkey")
-
-        self.set_hotkey(keypair, encrypt=use_password, overwrite=overwrite)
-        return self
-
-    def regenerate_coldkeypub(
-        self,
-        ss58_address: Optional[str] = None,
-        public_key: Optional[Union[str, bytes]] = None,
-        overwrite: bool = False,
-    ) -> "Wallet":
-        """Regenerates the coldkeypub from the passed ``ss58_address`` or public_key and saves the file. Requires either ``ss58_address`` or public_key to be passed.
-
-        Args:
-            ss58_address: (str, optional): Address as ``ss58`` string.
-            public_key: (str | bytes, optional): Public key as hex string or bytes.
-            overwrite (bool, optional) (default: False): Determines if this operation overwrites the coldkeypub (if exists) under the same path ``<wallet path>/<wallet name>/coldkeypub``.
-
-        Returns:
-            wallet (Wallet):
-                Newly re-generated wallet with coldkeypub.
-
-        """
-        if ss58_address is None and public_key is None:
-            raise ValueError("Either ss58_address or public_key must be passed")
-
-        if not is_valid_bittensor_address_or_public_key(
-            ss58_address if ss58_address is not None else public_key
-        ):
-            raise ValueError(
-                f"Invalid {'ss58_address' if ss58_address is not None else 'public_key'}."
-            )
-
-        if ss58_address is not None:
-            ss58_format = get_ss58_format(ss58_address)
-            keypair = Keypair(
-                ss58_address=ss58_address,
-                public_key=public_key,
-                ss58_format=ss58_format,
-            )
-        else:
-            keypair = Keypair(
-                ss58_address=ss58_address,
-                public_key=public_key,
-                ss58_format=SS58_FORMAT,
-            )
-
-        # No need to encrypt the public key
-        self.set_coldkeypub(keypair, overwrite=overwrite)
-        return self
-
-    @overload
-    def regenerate_coldkey(
-        self,
-        mnemonic: Optional[Union[list, str]] = None,
-        use_password: bool = True,
-        overwrite: bool = False,
-        suppress: bool = False,
-    ) -> "Wallet": ...
-
-    @overload
-    def regenerate_coldkey(
-        self,
-        seed: Optional[str] = None,
-        use_password: bool = True,
-        overwrite: bool = False,
-        suppress: bool = False,
-    ) -> "Wallet": ...
-
-    @overload
-    def regenerate_coldkey(
-        self,
-        json: Optional[Tuple[Union[str, Dict], str]] = None,
-        use_password: bool = True,
-        overwrite: bool = False,
-        suppress: bool = False,
-    ) -> "Wallet": ...
-
-    def regenerate_coldkey(
-        self,
-        use_password: bool = True,
-        overwrite: bool = False,
-        suppress: bool = False,
-        **kwargs,
-    ) -> "Wallet":
-        """Regenerates the coldkey from the passed mnemonic or seed, or JSON encrypts it with the user's password and saves the file.
-
-        Args:
-            use_password (bool, optional): Is the created key password protected.
-            overwrite (bool, optional): Determines if this operation overwrites the coldkey under the same path ``<wallet path>/<wallet name>/coldkey``.
-            suppress (bool, optional): If ``True``, suppresses the display of the mnemonic message. Defaults to ``False``.
-            kwargs["mnemonic"]: (Union[list, str], optional item of kwargs): Key mnemonic as list of words or string space separated words.
-            kwargs["seed"]: (str, optional item of kwargs): Seed as hex string.
-            kwargs["json"]: (Tuple[Union[str, Dict], str], optional item of kwargs): Restore from encrypted JSON backup as ``(json_data: Union[str, Dict], passphrase: str)``
-
-        Returns:
-            wallet (Wallet):
-                This object with newly created coldkey.
-
-        Note:
-            Uses priority order: ``mnemonic > seed > json``.
-        """
-        if len(kwargs) == 0:
-            raise ValueError("Must pass either mnemonic, seed, or json")
-
-        # Get from kwargs
-        mnemonic: Optional[Union[list, str]] = kwargs.get("mnemonic", None)
-        seed: Optional[str] = kwargs.get("seed", None)
-        json: Optional[Tuple[Union[str, Dict], str]] = kwargs.get("json", None)
-
-        if mnemonic is None and seed is None and json is None:
-            raise ValueError("Must pass either mnemonic, seed, or json")
-
-        if mnemonic is not None:
-            if isinstance(mnemonic, str):
-                mnemonic = mnemonic.split()
-
-            elif isinstance(mnemonic, list) and len(mnemonic) == 1:
-                mnemonic = mnemonic[0].split()
-
-            if len(mnemonic) not in [12, 15, 18, 21, 24]:
-                raise ValueError(
-                    "Mnemonic has invalid size. This should be 12,15,18,21 or 24 words"
-                )
-            keypair = Keypair.create_from_mnemonic(
-                " ".join(mnemonic), ss58_format=SS58_FORMAT
-            )
-
-            if not suppress:
-                display_mnemonic_msg(keypair, "coldkey")
-
-        elif seed is not None:
-            keypair = Keypair.create_from_seed(seed, ss58_format=SS58_FORMAT)
-
-        else:
-            # json is not None
-            if (
-                not isinstance(json, tuple)
-                or len(json) != 2
-                or not isinstance(json[0], (str, dict))
-                or not isinstance(json[1], str)
-            ):
-                raise ValueError(
-                    "json must be a tuple of (json_data: str | Dict, passphrase: str)"
-                )
-
-            json_data, passphrase = json
-            keypair = Keypair.create_from_encrypted_json(
-                json_data, passphrase, ss58_format=SS58_FORMAT
-            )
-
-        self.set_coldkey(keypair, encrypt=use_password, overwrite=overwrite)
-        self.set_coldkeypub(keypair, overwrite=overwrite)
-        return self
-
-    @overload
-    def regenerate_hotkey(
-        self,
-        *,
-        mnemonic: Optional[Union[list, str]] = None,
-        use_password: bool = True,
-        overwrite: bool = False,
-        suppress: bool = False,
-    ) -> "Wallet": ...
-
-    @overload
-    def regenerate_hotkey(
-        self,
-        *,
-        seed: Optional[str] = None,
-        use_password: bool = True,
-        overwrite: bool = False,
-        suppress: bool = False,
-    ) -> "Wallet": ...
-
-    @overload
-    def regenerate_hotkey(
-        self,
-        *,
-        json: Optional[Tuple[Union[str, Dict], str]] = None,
-        use_password: bool = True,
-        overwrite: bool = False,
-        suppress: bool = False,
-    ) -> "Wallet": ...
-
-    def regenerate_hotkey(
-        self,
-        *,
-        use_password: bool = True,
-        overwrite: bool = False,
-        suppress: bool = False,
-        **kwargs,
-    ) -> "Wallet":
-        """Regenerates the hotkey from passed mnemonic or seed, encrypts it with the user's password and saves the file.
-
-        Args:
-            kwargs["mnemonic"]: (Union[list, str], optional): Key mnemonic as list of words or string space separated words.
-            kwargs["seed"]: (str, optional): Seed as hex string.
-            kwargs["json"]: (Tuple[Union[str, Dict], str], optional): Restore from encrypted JSON backup as ``(json_data: Union[str, Dict], passphrase: str)``.
-            use_password (bool, optional): Is the created key password protected.
-            overwrite (bool, optional): Determines if this operation overwrites the hotkey under the same path ``<wallet path>/<wallet name>/hotkeys/<hotkey>``.
-            suppress (bool, optional): If ``True``, suppresses the display of the mnemonic message. Defaults to ``False``.
-
-        Returns:
-            wallet (Wallet):
-                This object with newly created hotkey.
-        """
-        if len(kwargs) == 0:
-            raise ValueError("Must pass either mnemonic, seed, or json")
-
-        # Get from kwargs
-        mnemonic: Optional[Union[list, str]] = kwargs.get("mnemonic", None)
-        seed: Optional[str] = kwargs.get("seed", None)
-        json: Optional[Tuple[Union[str, Dict], str]] = kwargs.get("json", None)
-
-        if mnemonic is None and seed is None and json is None:
-            raise ValueError("Must pass either mnemonic, seed, or json")
-
-        if mnemonic is not None:
-            if isinstance(mnemonic, str):
-                mnemonic = mnemonic.split()
-            if len(mnemonic) not in [12, 15, 18, 21, 24]:
-                raise ValueError(
-                    "Mnemonic has invalid size. This should be 12, 15, 18, 21 or 24 words."
-                )
-            keypair = Keypair.create_from_mnemonic(
-                " ".join(mnemonic), ss58_format=SS58_FORMAT
-            )
-            if not suppress:
-                display_mnemonic_msg(keypair, "hotkey")
-
-        elif seed is not None:
-            keypair = Keypair.create_from_seed(seed, ss58_format=SS58_FORMAT)
-
-        else:
-            # json is not None
-            if (
-                not isinstance(json, tuple)
-                or len(json) != 2
-                or not isinstance(json[0], (str, dict))
-                or not isinstance(json[1], str)
-            ):
-                raise ValueError(
-                    "json must be a tuple of (json_data: str | Dict, passphrase: str)"
-                )
-
-            json_data, passphrase = json
-            keypair = Keypair.create_from_encrypted_json(
-                json_data, passphrase, ss58_format=SS58_FORMAT
-            )
-
-        self.set_hotkey(keypair, encrypt=use_password, overwrite=overwrite)
-        return self
diff --git a/bittensor_wallet/wallet/__init__.py b/bittensor_wallet/wallet/__init__.py
new file mode 100644
index 0000000..5a7bd36
--- /dev/null
+++ b/bittensor_wallet/wallet/__init__.py
@@ -0,0 +1,4 @@
+from bittensor_wallet.bittensor_wallet import wallet as _
+
+display_mnemonic_msg = _.display_mnemonic_msg
+Wallet = _.Wallet
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..8fea4cc
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,79 @@
+[project]
+name = "bittensor-wallet"
+version = "2.0.0"
+description = ""
+readme = "README.md"
+license = {file = "LICENSE"}
+keywords = ["substrate", "scale", "codec", "bittensor", "wallet"]
+
+dependencies = [
+    "termcolor",
+    "eth-utils<2.3.0",
+    "password_strength",
+    "cryptography~=42.0.5",
+    "ansible~=6.7",
+    "ansible_vault~=2.1",
+    "munch~=2.5.0",
+    "rich",
+    "py-bip39-bindings==0.1.11"
+]
+requires-python = ">= 3.9"
+
+authors = [
+  {name = "Cameron Fairchild", email = "cameron@opentensor.dev"},
+  {name = "Opentensor Foundation", email = "hello@bittensor.com"},
+]
+maintainers = [
+  {name = "Cameron Fairchild", email = "cameron@opentensor.dev"}
+]
+classifiers = [
+        "Development Status :: 5 - Production/Stable",
+        "Intended Audience :: Developers",
+        "Topic :: Software Development :: Build Tools",
+        "License :: OSI Approved :: MIT License",
+        "Programming Language :: Python :: 3 :: Only",
+        "Programming Language :: Python :: 3.9",
+        "Programming Language :: Python :: 3.10",
+        "Programming Language :: Python :: 3.11",
+        "Programming Language :: Python :: 3.12",
+        "Topic :: Scientific/Engineering",
+        "Topic :: Scientific/Engineering :: Mathematics",
+        "Topic :: Scientific/Engineering :: Artificial Intelligence",
+        "Topic :: Software Development",
+        "Topic :: Software Development :: Libraries",
+        "Topic :: Software Development :: Libraries :: Python Modules",]
+
+[project.urls]
+Repository = "https://github.com/opentensor/btwallet"
+
+[build-system]
+requires = ["maturin>=1.0,<2.0"]
+build-backend = "maturin"
+
+[tool.maturin]
+include = ["bittensor_wallet*", "src*"]
+exclude = ["tests*"]
+
+[project.optional-dependencies]
+dev = [
+    "pytest==7.2.0",
+    "pytest-asyncio==0.23.7",
+    "pytest-mock==3.12.0",
+    "pytest-split==0.8.0",
+    "pytest-xdist==3.0.2",
+    "pytest-rerunfailures==10.2",
+    "coveralls==3.3.1",
+    "pytest-cov==4.0.0",
+    "ddt==1.6.0",
+    "hypothesis==6.81.1",
+    "flake8==7.0.0",
+    "mypy==1.8.0",
+    "types-retry==0.9.9.4",
+    "freezegun==1.5.0",
+    "httpx==0.27.0",
+    "ruff==0.4.7",
+    "aioresponses==0.7.6",
+    "factory-boy==3.3.0",
+    "maturin==1.7.0",
+    "py-bip39-bindings==0.1.11",
+]
\ No newline at end of file
diff --git a/requirements/dev.txt b/requirements/dev.txt
index 6344158..9fa4df0 100644
--- a/requirements/dev.txt
+++ b/requirements/dev.txt
@@ -16,3 +16,5 @@ httpx==0.27.0
 ruff==0.4.7
 aioresponses==0.7.6
 factory-boy==3.3.0
+maturin==1.7.0
+py-bip39-bindings==0.1.11
\ No newline at end of file
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 59d4145..0000000
--- a/setup.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# The MIT License (MIT)
-# Copyright © 2023 Yuma Rao
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
-# documentation files (the “Software”), to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
-
-from setuptools import setup, find_packages
-from os import path
-from io import open
-import codecs
-import re
-import os
-import pathlib
-
-
-def read_requirements(path_):
-    requirements_ = []
-
-    with pathlib.Path(path_).open() as requirements_txt:
-        for line in requirements_txt:
-            if line.startswith("git+"):
-                pkg_name = re.search(r"egg=([a-zA-Z0-9_-]+)", line.strip()).group(1)
-                requirements_.append(pkg_name + " @ " + line.strip())
-            else:
-                requirements_.append(line.strip())
-
-    return requirements_
-
-
-requirements = read_requirements("requirements/prod.txt")
-extra_requirements_dev = read_requirements("requirements/dev.txt")
-
-here = path.abspath(path.dirname(__file__))
-
-with open(path.join(here, "README.md"), encoding="utf-8") as f:
-    long_description = f.read()
-
-
-# loading version from setup.py
-with codecs.open(
-    os.path.join(here, "bittensor_wallet/__init__.py"), encoding="utf-8"
-) as init_file:
-    version_match = re.search(
-        r"^__version__ = ['\"]([^'\"]*)['\"]", init_file.read(), re.M
-    )
-    version_string = version_match.group(1)
-
-setup(
-    name="bittensor-wallet",
-    version=version_string,
-    description="",
-    long_description=long_description,
-    long_description_content_type="text/markdown",
-    url="https://github.com/opentensor/btwallet",
-    author="bittensor.com",
-    packages=find_packages(exclude=["tests", "tests.*", "test_*.py"]),
-    include_package_data=True,
-    author_email="",
-    license="MIT",
-    python_requires=">=3.9",
-    install_requires=requirements,
-    extras_require={
-        "dev": extra_requirements_dev,
-    },
-    classifiers=[
-        "Development Status :: 5 - Production/Stable",
-        "Intended Audience :: Developers",
-        "Topic :: Software Development :: Build Tools",
-        "License :: OSI Approved :: MIT License",
-        "Programming Language :: Python :: 3 :: Only",
-        "Programming Language :: Python :: 3.9",
-        "Programming Language :: Python :: 3.10",
-        "Programming Language :: Python :: 3.11",
-        "Programming Language :: Python :: 3.12",
-        "Topic :: Scientific/Engineering",
-        "Topic :: Scientific/Engineering :: Mathematics",
-        "Topic :: Scientific/Engineering :: Artificial Intelligence",
-        "Topic :: Software Development",
-        "Topic :: Software Development :: Libraries",
-        "Topic :: Software Development :: Libraries :: Python Modules",
-    ],
-)
diff --git a/src/config.rs b/src/config.rs
new file mode 100644
index 0000000..891dad4
--- /dev/null
+++ b/src/config.rs
@@ -0,0 +1,68 @@
+use crate::constants::{BT_WALLET_HOTKEY, BT_WALLET_NAME, BT_WALLET_PATH};
+use pyo3::prelude::*;
+
+#[derive(Clone)]
+pub struct WalletConfig {
+    pub name: String,
+    pub path: String,
+    pub hotkey: String,
+}
+
+impl WalletConfig {
+    pub fn new(name: Option<String>, hotkey: Option<String>, path: Option<String>) -> Self {
+        WalletConfig {
+            name: name.unwrap_or_else(|| BT_WALLET_NAME.to_string()),
+            hotkey: hotkey.unwrap_or_else(|| BT_WALLET_HOTKEY.to_string()),
+            path: path.unwrap_or_else(|| BT_WALLET_PATH.to_string()),
+        }
+    }
+}
+
+#[derive(Clone)]
+#[pyclass(subclass)]
+pub struct Config {
+    pub wallet: WalletConfig,
+}
+
+#[pymethods]
+impl Config {
+    #[new]
+    #[pyo3(signature = (name = None, hotkey = None, path = None))]
+    pub fn new(
+        name: Option<String>,
+        hotkey: Option<String>,
+        path: Option<String>,
+    ) -> PyResult<Config> {
+        Ok(Config {
+            wallet: WalletConfig::new(name, hotkey, path),
+        })
+    }
+    fn __str__(&self) -> PyResult<String> {
+        Ok(format!(
+            "Config(name: '{}', path: '~/{}', hotkey: '{}')",
+            self.wallet.name, self.wallet.path, self.wallet.hotkey
+        ))
+    }
+
+    fn __repr__(&self) -> PyResult<String> {
+        self.__str__()
+    }
+
+    /// Returns wallet name
+    #[getter]
+    pub fn name(&self) -> PyResult<String> {
+        Ok(self.wallet.name.clone())
+    }
+
+    /// Returns wallet name
+    #[getter]
+    pub fn path(&self) -> PyResult<String> {
+        Ok(self.wallet.path.clone())
+    }
+
+    /// Returns wallet name
+    #[getter]
+    pub fn hotkey(&self) -> PyResult<String> {
+        Ok(self.wallet.hotkey.clone())
+    }
+}
diff --git a/src/constants.rs b/src/constants.rs
new file mode 100644
index 0000000..e54b3b1
--- /dev/null
+++ b/src/constants.rs
@@ -0,0 +1,3 @@
+pub const BT_WALLET_NAME: &str = "default";
+pub const BT_WALLET_HOTKEY: &str = "default";
+pub const BT_WALLET_PATH: &str = ".bittensor/wallets/";
diff --git a/src/errors.rs b/src/errors.rs
new file mode 100644
index 0000000..0ee77e8
--- /dev/null
+++ b/src/errors.rs
@@ -0,0 +1,61 @@
+use pyo3::exceptions::PyException;
+use pyo3::prelude::*;
+use std::{error, fmt};
+
+#[pyclass(extends=PyException)]
+#[derive(Debug)]
+pub struct KeyFileError {
+    pub message: String,
+}
+
+/// Error thrown when the keyfile is corrupt, non-writable, non-readable or the password used to decrypt is invalid.
+#[pymethods]
+impl KeyFileError {
+    #[new]
+    #[pyo3(signature = (message=None))]
+    pub fn new(message: Option<String>) -> Self {
+        let msg = message.unwrap_or_default();
+        KeyFileError { message: msg }
+    }
+
+    pub fn __str__(&self) -> String {
+        self.message.clone()
+    }
+}
+
+impl fmt::Display for KeyFileError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "KeyFileError: {}", self.message)
+    }
+}
+
+impl error::Error for KeyFileError {}
+
+#[pyclass(extends=PyException)]
+#[derive(Debug)]
+pub struct ConfigurationError {
+    pub message: String,
+}
+
+/// ConfigurationError
+#[pymethods]
+impl ConfigurationError {
+    #[new]
+    #[pyo3(signature = (message=None))]
+    pub fn new(message: Option<String>) -> Self {
+        let msg = message.unwrap_or_default();
+        ConfigurationError { message: msg }
+    }
+
+    pub fn __str__(&self) -> String {
+        self.message.clone()
+    }
+}
+
+impl fmt::Display for ConfigurationError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ConfigurationError: {}", self.message)
+    }
+}
+
+impl error::Error for ConfigurationError {}
diff --git a/src/keyfile.rs b/src/keyfile.rs
new file mode 100644
index 0000000..49b4cef
--- /dev/null
+++ b/src/keyfile.rs
@@ -0,0 +1,986 @@
+// use pyo3::exceptions::{
+//     PyFileNotFoundError, PyIOError, PyOSError, PyPermissionError, PyRuntimeError, PyUnicodeDecodeError, PyValueError
+// };
+use pyo3::prelude::*;
+use pyo3::types::{PyBytes, PyString};
+
+use std::collections::HashMap;
+use std::env;
+use std::fs;
+use std::io::{Read, Write};
+use std::os::unix::fs::PermissionsExt;
+use std::path::Path;
+use std::str::from_utf8;
+
+use ansible_vault::{decrypt_vault, encrypt_vault};
+use fernet::Fernet;
+
+use passwords::analyzer;
+use passwords::scorer;
+use serde_json::json;
+
+use crate::errors::KeyFileError;
+use crate::keypair::Keypair;
+use crate::utils;
+
+type PyFileNotFoundError = KeyFileError;
+type PyIOError = KeyFileError;
+type PyOSError = KeyFileError;
+type PyPermissionError = KeyFileError;
+type PyRuntimeError = KeyFileError;
+type PyUnicodeDecodeError = KeyFileError;
+type PyValueError = KeyFileError;
+
+use sodiumoxide::crypto::pwhash;
+use sodiumoxide::crypto::secretbox;
+
+const NACL_SALT: &[u8] = b"\x13q\x83\xdf\xf1Z\t\xbc\x9c\x90\xb5Q\x879\xe9\xb1";
+const LEGACY_SALT: &[u8] = b"Iguesscyborgslikemyselfhaveatendencytobeparanoidaboutourorigins";
+
+/// Serializes keypair object into keyfile data.
+///
+///     Args:
+///         keypair (Keypair): The keypair object to be serialized.
+///     Returns:
+///         data (bytes): Serialized keypair data.
+#[pyfunction]
+#[pyo3(signature = (keypair))]
+pub fn serialized_keypair_to_keyfile_data(py: Python, keypair: &Keypair) -> PyResult<PyObject> {
+    let mut data: HashMap<&str, serde_json::Value> = HashMap::new();
+
+    // publicKey and privateKey fields are optional. If they exist, hex prefix "0x" is added to them.
+    if let Ok(Some(public_key)) = keypair.public_key(py) {
+        let public_bytes: &PyBytes = public_key.extract(py)?;
+        let public_key_str = hex::encode(public_bytes.as_bytes());
+        data.insert("accountId", json!(format!("0x{}", public_key_str)));
+        data.insert("publicKey", json!(format!("0x{}", public_key_str)));
+    }
+    if let Ok(Some(private_key)) = &keypair.private_key(py) {
+        let private_bytes: &PyBytes = private_key.extract(py)?;
+        let private_key_str = hex::encode(private_bytes.as_bytes());
+        data.insert("privateKey", json!(format!("0x{}", private_key_str)));
+    }
+
+    // mnemonic and ss58_address fields are optional.
+    if let Ok(Some(mnemonic)) = &keypair.mnemonic() {
+        data.insert("secretPhrase", json!(mnemonic));
+    }
+
+    // the seed_hex field is optional. If it exists, hex prefix "0x" is added to it.
+    if let Ok(Some(seed_hex_obj)) = keypair.seed_hex(py) {
+        let seed_hex = seed_hex_obj
+            .extract::<Vec<u8>>(py)
+            .unwrap_or_else(|_| Vec::new());
+        let seed_hex_str = match from_utf8(&seed_hex) {
+            Ok(s) => s.to_string(),
+            Err(_) => hex::encode(seed_hex),
+        };
+        data.insert("secretSeed", json!(format!("0x{}", seed_hex_str)));
+    }
+
+    if let Ok(Some(ss58_address)) = &keypair.ss58_address() {
+        data.insert("ss58Address", json!(ss58_address));
+    }
+
+    // Serialize the data into JSON string and return it as bytes
+    let json_data = serde_json::to_string(&data).map_err(|e| {
+        PyErr::new::<PyUnicodeDecodeError, _>(format!("Serialization error: {}", e))
+    })?;
+    Ok(PyBytes::new_bound(py, &json_data.into_bytes()).into_py(py))
+}
+
+/// Deserializes Keypair object from passed keyfile data.
+///
+///     Args:
+///         keyfile_data (PyBytes): The keyfile data to be loaded.
+///     Returns:
+///         keypair (Keypair): The Keypair loaded from bytes.
+///     Raises:
+///         KeyFileError: Raised if the passed PyBytes cannot construct a keypair object.
+#[pyfunction]
+#[pyo3(signature = (keyfile_data))]
+pub fn deserialize_keypair_from_keyfile_data(
+    keyfile_data: &[u8],
+    py: Python<'_>,
+) -> PyResult<Keypair> {
+    // Decode the keyfile data from PyBytes to a string
+    let decoded = from_utf8(keyfile_data)
+        .map_err(|_| PyErr::new::<PyUnicodeDecodeError, _>("Failed to decode keyfile data."))?;
+
+    // Parse the JSON string into a HashMap
+    let keyfile_dict: HashMap<String, Option<String>> = serde_json::from_str(decoded)
+        .map_err(|_| PyErr::new::<KeyFileError, _>("Failed to parse keyfile data."))?;
+
+    // Extract data from the keyfile
+    let secret_seed = keyfile_dict.get("secretSeed").and_then(|v| v.clone());
+    let secret_phrase = keyfile_dict.get("secretPhrase").and_then(|v| v.clone());
+    let private_key = keyfile_dict.get("privateKey").and_then(|v| v.clone());
+    let ss58_address = keyfile_dict.get("ss58Address").and_then(|v| v.clone());
+
+    // Create the `Keypair` based on the available data
+    let keypair = if let Some(secret_phrase) = secret_phrase {
+        Keypair::create_from_mnemonic(secret_phrase.as_str())
+    } else if secret_seed.is_some() {
+        let seed_string: &Bound<PyAny> = &PyString::new_bound(py, secret_seed.unwrap().as_str());
+        Keypair::create_from_seed(&seed_string.clone())
+    } else if let Some(private_key) = private_key {
+        Keypair::create_from_private_key(private_key.as_str())
+    } else if ss58_address.is_some() {
+        Ok(Keypair::new(ss58_address, None, None, 42, None, 1)?)
+    } else {
+        return Err(PyErr::new::<PyOSError, _>(
+            "Keypair could not be created from keyfile data.",
+        ));
+    };
+    keypair
+}
+
+/// Validates the password against a password policy.
+///
+///     Args:
+///         password (str): The password to verify.
+///     Returns:
+///         valid (bool): ``True`` if the password meets validity requirements.
+#[pyfunction]
+#[pyo3(signature = (password))]
+pub fn validate_password(_py: Python, password: &str) -> PyResult<bool> {
+    // Check for an empty password
+    if password.is_empty() {
+        return Ok(false);
+    }
+
+    // Define the password policy
+    let min_length = 6;
+    let min_score = 20.0; // Adjusted based on the scoring system described in the documentation
+
+    // Analyze the password
+    let analyzed = analyzer::analyze(password);
+    let score = scorer::score(&analyzed);
+
+    // Check conditions
+    if password.len() >= min_length && score >= min_score {
+        // Prompt user to retype the password
+        let password_verification_response =
+            utils::prompt_password("Retype your password: ".to_string())
+                .expect("Failed to read the password.");
+
+        // Remove potential newline or whitespace at the end
+        let password_verification = password_verification_response.trim();
+
+        if password == password_verification {
+            Ok(true)
+        } else {
+            utils::print("Passwords do not match.\n".to_string());
+            Ok(false)
+        }
+    } else {
+        utils::print("Password not strong enough. Try increasing the length of the password or the password complexity.".to_string());
+        Ok(false)
+    }
+}
+
+/// Prompts the user to enter a password for key encryption.
+///
+///     Returns:
+///         password (str): The valid password entered by the user.
+#[pyfunction]
+pub fn ask_password(py: Python) -> PyResult<String> {
+
+    let mut valid = false;
+    let password = utils::prompt_password("Enter your password: ".to_string());
+
+    while !valid {
+        if let Some(ref password) = password {
+            valid = validate_password(py, &password)?;
+        } else {
+            valid = true
+        }
+    }
+
+    Ok(password.unwrap_or("".to_string()).trim().to_string())
+}
+
+/// Returns `true` if the keyfile data is NaCl encrypted.
+///
+/// # Arguments
+///
+/// * `keyfile_data` - Bytes to validate
+///
+/// # Returns
+///
+/// * `is_nacl` - `true` if the data is ansible encrypted.
+#[pyfunction]
+pub fn keyfile_data_is_encrypted_nacl(_py: Python, keyfile_data: &[u8]) -> PyResult<bool> {
+    if keyfile_data.starts_with(b"$NACL") {
+        return Ok(true);
+    }
+    Ok(false)
+}
+
+/// Returns true if the keyfile data is ansible encrypted.
+///
+/// # Args
+/// * `keyfile_data` - The bytes to validate.
+///
+/// # Returns
+/// * `is_ansible` - True if the data is ansible encrypted.
+#[pyfunction]
+pub fn keyfile_data_is_encrypted_ansible(_py: Python, keyfile_data: &[u8]) -> PyResult<bool> {
+    if keyfile_data.starts_with(b"$ANSIBLE_VAULT") {
+        return Ok(true);
+    }
+    Ok(false)
+}
+
+/// Returns true if the keyfile data is legacy encrypted.
+///
+/// # Args
+/// * `keyfile_data` - The bytes to validate.
+///
+/// # Returns
+/// * `is_legacy` - `true` if the data is legacy encrypted.
+#[pyfunction]
+pub fn keyfile_data_is_encrypted_legacy(_py: Python, keyfile_data: &[u8]) -> PyResult<bool> {
+    if keyfile_data.starts_with(b"gAAAAA") {
+        return Ok(true);
+    }
+    Ok(false)
+}
+
+/// Returns `true` if the keyfile data is encrypted.
+///
+///     Args:
+///         keyfile_data (bytes): The bytes to validate.
+///
+///     Returns:
+///         is_encrypted (bool): `true` if the data is encrypted.
+#[pyfunction]
+#[pyo3(signature = (keyfile_data))]
+pub fn keyfile_data_is_encrypted(_py: Python, keyfile_data: &[u8]) -> PyResult<bool> {
+    let nacl = keyfile_data_is_encrypted_nacl(_py, keyfile_data)?;
+    let ansible = keyfile_data_is_encrypted_ansible(_py, keyfile_data)?;
+    let legacy = keyfile_data_is_encrypted_legacy(_py, keyfile_data)?;
+    Ok(nacl || ansible || legacy)
+}
+
+/// Returns type of encryption method as a string.
+///
+///     Arguments:
+///         keyfile_data (bytes): Bytes to validate.
+///
+///     Returns:
+///         (str): A string representing the name of encryption method.
+#[pyfunction]
+#[pyo3(signature = (keyfile_data))]
+pub fn keyfile_data_encryption_method(py: Python, keyfile_data: &[u8]) -> PyResult<String> {
+    let encryption_method = match true {
+        _ if keyfile_data_is_encrypted_nacl(py, keyfile_data)? => "NaCl",
+        _ if keyfile_data_is_encrypted_ansible(py, keyfile_data)? => "Ansible Vault",
+        _ if keyfile_data_is_encrypted_legacy(py, keyfile_data)? => "legacy",
+        _ => "unknown",
+    };
+
+    Ok(encryption_method.to_string())
+}
+
+/// legacy_encrypt_keyfile_data.
+///
+///     Arguments:
+///         keyfile_data (bytes): Bytes of data from the keyfile.
+///         password (str): Optional string that represents the password.
+///
+///     Returns:
+///         encrypted_data (bytes): The encrypted keyfile data in bytes.
+#[pyfunction]
+#[pyo3(signature = (keyfile_data, password))]
+pub fn legacy_encrypt_keyfile_data(
+    py: Python,
+    keyfile_data: &[u8],
+    password: Option<String>,
+) -> PyResult<PyObject> {
+    let password = password.unwrap_or_else(||
+        // function to get password from user
+        ask_password(py).unwrap());
+
+    utils::print(":exclamation_mark: Encrypting key with legacy encryption method...".to_string());
+
+    // Encrypting key with legacy encryption method
+    let encrypted_data = encrypt_vault(keyfile_data, password.as_str())
+        .map_err(|err| PyErr::new::<KeyFileError, _>(format!("{}", err)))?;
+
+    Ok(PyBytes::new_bound(py, &encrypted_data.into_bytes()).into_py(py))
+}
+
+/// Retrieves the cold key password from the environment variables.
+///
+/// # Args
+/// * `coldkey_name` - The name of the cold key.
+///
+/// # Returns
+/// * `Option<String>` - The password retrieved from the environment variables, or `None` if not found.
+#[pyfunction]
+#[pyo3(signature = (coldkey_name))]
+pub fn get_coldkey_password_from_environment(
+    _py: Python,
+    coldkey_name: String,
+) -> PyResult<Option<String>> {
+    let env_key: String = format!(
+        "BT_COLD_PW_{}",
+        coldkey_name.to_uppercase().replace('-', "_")
+    );
+    Ok(env::var(env_key).ok())
+}
+
+// decrypt of keyfile_data with secretbox
+fn derive_key(password: &[u8]) -> secretbox::Key {
+    let nacl_salt = pwhash::argon2i13::Salt::from_slice(NACL_SALT).expect("Invalid NACL_SALT.");
+    let mut key = secretbox::Key([0; secretbox::KEYBYTES]);
+    pwhash::argon2i13::derive_key(
+        &mut key.0,
+        password,
+        &nacl_salt,
+        pwhash::argon2i13::OPSLIMIT_SENSITIVE,
+        pwhash::argon2i13::MEMLIMIT_SENSITIVE,
+    )
+    .expect("Failed to derive key for NaCl decryption.");
+    key
+}
+
+/// Encrypts the passed keyfile data using ansible vault.
+///
+///     Args
+///         keyfile_data (bytes): The bytes to encrypt.
+///         password (str): The password used to encrypt the data. If `None`, asks for user input.
+///
+///     Returns
+///         encrypted_data (bytes): The encrypted data.
+#[pyfunction]
+#[pyo3(signature = (keyfile_data, password))]
+pub fn encrypt_keyfile_data(
+    py: Python,
+    keyfile_data: &[u8],
+    password: Option<String>,
+) -> PyResult<PyObject> {
+    // get password or ask user
+    let password = match password {
+        Some(pwd) => pwd,
+        None => ask_password(py)?,
+    };
+
+    utils::print("Encrypting...".to_string());
+
+    // crate the key with pwhash Argon2i
+    let key = derive_key(password.as_bytes());
+
+    // encrypt the data using SecretBox
+    let nonce = secretbox::gen_nonce();
+    let encrypted_data = secretbox::seal(keyfile_data, &nonce, &key);
+
+    // concatenate with b"$NACL"
+    let mut result = b"$NACL".to_vec();
+    result.extend_from_slice(&nonce.0);
+    result.extend_from_slice(&encrypted_data);
+
+    // return result as bytes for python
+    Ok(PyBytes::new_bound(py, &result).into())
+}
+
+/// Decrypts the passed keyfile data using ansible vault.
+///
+///     Args
+///         keyfile_data (): The bytes to decrypt.
+///         password (str): The password used to decrypt the data. If `None`, asks for user input.
+///         coldkey_name (str): The name of the cold key. If provided, retrieves the password from environment variables.
+///
+///     Returns
+///         decrypted_data (bytes): The decrypted data.
+#[pyfunction]
+#[pyo3(signature = (keyfile_data, password = None, coldkey_name = None))]
+pub fn decrypt_keyfile_data(
+    py: Python,
+    keyfile_data: &[u8],
+    password: Option<String>,
+    coldkey_name: Option<String>,
+) -> PyResult<PyObject> {
+    // decrypt of keyfile_data with secretbox
+    fn nacl_decrypt(keyfile_data: &[u8], key: &secretbox::Key) -> PyResult<Vec<u8>> {
+        let data = &keyfile_data[5..]; // Remove the $NACL prefix
+        let nonce = secretbox::Nonce::from_slice(&data[0..secretbox::NONCEBYTES])
+            .ok_or(PyErr::new::<PyRuntimeError, _>("Invalid nonce."))?;
+        let ciphertext = &data[secretbox::NONCEBYTES..];
+        secretbox::open(ciphertext, &nonce, key)
+            .map_err(|_| PyErr::new::<KeyFileError, _>("Wrong password for nacl decryption."))
+    }
+
+    // decrypt of keyfile_data with legacy way
+    fn legacy_decrypt(password: &str, keyfile_data: &[u8]) -> PyResult<Vec<u8>> {
+        let kdf = pbkdf2::pbkdf2_hmac::<sha2::Sha256>;
+        let mut key = vec![0; 32];
+        kdf(password.as_bytes(), LEGACY_SALT, 10000000, &mut key);
+
+        let fernet_key = Fernet::generate_key();
+        let fernet = Fernet::new(&fernet_key).unwrap();
+        let keyfile_data_str = from_utf8(keyfile_data)?;
+        fernet
+            .decrypt(keyfile_data_str)
+            .map_err(|_| PyErr::new::<KeyFileError, _>("Wrong password for nacl decryption."))
+    }
+
+    let mut password = password;
+
+    // Retrieve password from environment variable if coldkey_name is provided
+    if let Some(coldkey) = coldkey_name {
+        if password.is_none() {
+            password = get_coldkey_password_from_environment(py, coldkey)?;
+        }
+    }
+
+    // If password is still None, ask the user for input
+    if password.is_none() {
+        password = Some(ask_password(py)?);
+    }
+
+    let password = password.unwrap();
+
+    utils::print("Decrypting...".to_string());
+
+    // NaCl decryption
+    if keyfile_data_is_encrypted_nacl(py, keyfile_data)? {
+        let key = derive_key(password.as_bytes());
+        let decrypted_data = nacl_decrypt(keyfile_data, &key)
+            .map_err(|_| PyErr::new::<KeyFileError, _>("Wrong password for decryption."))?;
+        return Ok(PyBytes::new_bound(py, &decrypted_data).into_py(py));
+    }
+
+    // Ansible Vault decryption
+    if keyfile_data_is_encrypted_ansible(py, keyfile_data)? {
+        let decrypted_data = decrypt_vault(keyfile_data, password.as_str())
+            .map_err(|_| PyErr::new::<KeyFileError, _>("Wrong password for decryption."))?;
+        return Ok(PyBytes::new_bound(py, &decrypted_data).into_py(py));
+    }
+
+    // Legacy decryption
+    if keyfile_data_is_encrypted_legacy(py, keyfile_data)? {
+        let decrypted_data = legacy_decrypt(&password, keyfile_data)
+            .map_err(|_| PyErr::new::<KeyFileError, _>("Wrong password for decryption."))?;
+        return Ok(PyBytes::new_bound(py, &decrypted_data).into_py(py));
+    }
+
+    // If none of the methods work, raise error
+    Err(PyErr::new::<KeyFileError, _>(
+        "Invalid or unknown encryption method.",
+    ))
+}
+
+fn confirm_prompt(question: &str) -> bool {
+    let choice = utils::prompt(format!("{} (y/N): ", question)).expect("Failed to read input.");
+    choice.trim().to_lowercase() == "y"
+}
+
+fn expand_tilde(path: &str) -> String {
+    if path.starts_with("~/") {
+        if let Some(home_dir) = dirs::home_dir() {
+            return path.replacen('~', home_dir.to_str().unwrap(), 1);
+        }
+    }
+    path.to_string()
+}
+
+#[derive(Clone)]
+#[pyclass(subclass)]
+pub struct Keyfile {
+    path: String,
+    name: String,
+}
+
+#[pymethods]
+impl Keyfile {
+    #[new]
+    #[pyo3(signature = (path, name = None))]
+    pub fn new(path: String, name: Option<String>) -> PyResult<Self> {
+        let path = expand_tilde(&path);
+        let name = name.unwrap_or_else(|| "Keyfile".to_string());
+        Ok(Keyfile { path, name })
+    }
+
+    #[allow(clippy::bool_comparison)]
+    fn __str__(&self, py: Python) -> PyResult<String> {
+        if self.exists_on_device()? != true {
+            Ok(format!("keyfile (empty, {})>", self.path))
+        } else if self.is_encrypted(py)? {
+            let encryption_method = self._read_keyfile_data_from_file(py)?;
+            Ok(format!(
+                "Keyfile ({:?} encrypted, {})>",
+                encryption_method, self.path
+            ))
+        } else {
+            Ok(format!("keyfile (decrypted, {})>", self.path))
+        }
+    }
+
+    fn __repr__(&self, py: Python) -> PyResult<String> {
+        self.__str__(py)
+    }
+
+    // TODO (devs): rust creates the same function automatically by `keypair` getter function and the error accuses. We need to understand how to avoid this.
+    /// Returns the keypair from path, decrypts data if the file is encrypted.
+    // #[getter]
+    // pub fn keypair(&self, py: Python) -> PyResult<bool>{
+    //     self.get_keypair(None, py)
+    // }
+
+    /// Returns the keypair from the path, decrypts data if the file is encrypted.
+    #[pyo3(signature = (password = None))]
+    pub fn get_keypair(&self, password: Option<String>, py: Python) -> PyResult<Keypair> {
+        // read file
+        let keyfile_data = self._read_keyfile_data_from_file(py)?;
+
+        let keyfile_data_bytes: &[u8] = keyfile_data.extract(py)?;
+
+        // check if encrypted
+        let decrypted_keyfile_data = if keyfile_data_is_encrypted(py, keyfile_data_bytes)? {
+            decrypt_keyfile_data(py, keyfile_data_bytes, password, Some(self.name.clone()))?
+        } else {
+            keyfile_data
+        };
+
+        // convert decrypted data to bytes
+        let decrypted_bytes: &[u8] = decrypted_keyfile_data.extract(py)?;
+
+        // deserialization data into the Keypair
+        deserialize_keypair_from_keyfile_data(decrypted_bytes, py)
+    }
+
+    /// Loads the name from keyfile.name or raises an error.
+    #[getter(name)]
+    pub fn get_name(&self) -> PyResult<String> {
+        Ok(self.name.clone())
+    }
+
+    /// Loads the name from keyfile.path or raises an error.
+    #[getter(path)]
+    pub fn get_path(&self) -> PyResult<String> {
+        Ok(self.path.clone())
+    }
+
+    /// Returns the keyfile data under path.
+    #[getter]
+    pub fn data(&self, py: Python) -> PyResult<PyObject> {
+        self._read_keyfile_data_from_file(py)
+    }
+
+    /// Returns the keyfile data under path.
+    #[getter]
+    pub fn keyfile_data(&self, py: Python) -> PyResult<PyObject> {
+        self._read_keyfile_data_from_file(py)
+    }
+
+    /// Writes the keypair to the file and optionally encrypts data.
+    #[pyo3(signature = (keypair, encrypt = true, overwrite = false, password = None))]
+    pub fn set_keypair(
+        &self,
+        keypair: Keypair,
+        encrypt: bool,
+        overwrite: bool,
+        password: Option<String>,
+        py: Python,
+    ) -> PyResult<()> {
+        self.make_dirs()?;
+
+        let keyfile_data = serialized_keypair_to_keyfile_data(py, &keypair)?;
+
+        let final_keyfile_data = if encrypt {
+            let encrypted_data = encrypt_keyfile_data(py, keyfile_data.extract(py)?, password)?;
+            encrypted_data.extract::<&[u8]>(py)?
+        } else {
+            keyfile_data.extract::<&[u8]>(py)?
+        };
+
+        self._write_keyfile_data_to_file(final_keyfile_data, overwrite)?;
+
+        Ok(())
+    }
+
+    /// Creates directories for the path if they do not exist.
+    pub fn make_dirs(&self) -> PyResult<()> {
+        // convert String to Path
+        let path: &Path = self.path.as_ref();
+        if let Some(directory) = path.parent() {
+            // check if the dir is exit already
+            if !directory.exists() {
+                // create the dir if not
+                fs::create_dir_all(directory)?;
+            }
+        }
+        Ok(())
+    }
+
+    /// Returns ``True`` if the file exists on the device.
+    ///
+    /// Returns:
+    ///     readable (bool): ``True`` if the file is readable.
+    pub fn exists_on_device(&self) -> PyResult<bool> {
+        Ok(Path::new(&self.path).exists())
+    }
+
+    /// Returns ``True`` if the file under path is readable.
+    pub fn is_readable(&self) -> PyResult<bool> {
+        // check file exist
+        if !self.exists_on_device()? {
+            return Ok(false);
+        }
+
+        // get file metadata
+        let metadata = fs::metadata(&self.path).map_err(|e| {
+            PyErr::new::<PyIOError, _>(format!("Failed to get metadata for file: {}.", e))
+        })?;
+
+        // check permissions
+        let permissions = metadata.permissions();
+        let readable = permissions.mode() & 0o444 != 0; // check readability
+
+        Ok(readable)
+    }
+
+    /// Returns ``True`` if the file under path is writable.
+    ///
+    /// Returns:
+    ///     writable (bool): ``True`` if the file is writable.
+    pub fn is_writable(&self) -> PyResult<bool> {
+        // check if file exist
+        if !self.exists_on_device()? {
+            return Ok(false);
+        }
+
+        // get file metadata
+        let metadata = fs::metadata(&self.path).map_err(|e| {
+            PyErr::new::<PyIOError, _>(format!("Failed to get metadata for file: {}", e))
+        })?;
+
+        // check the permissions
+        let permissions = metadata.permissions();
+        let writable = permissions.mode() & 0o222 != 0; // check if file is writable
+
+        Ok(writable)
+    }
+
+    /// Returns ``True`` if the file under path is encrypted.
+    ///
+    ///     Returns:
+    ///         encrypted (bool): ``True`` if the file is encrypted.
+    pub fn is_encrypted(&self, py: Python) -> PyResult<bool> {
+        // check if file exist
+        if !self.exists_on_device()? {
+            return Ok(false);
+        }
+
+        // check readable
+        if !self.is_readable()? {
+            return Ok(false);
+        }
+
+        // get the data from file
+        let keyfile_data = self._read_keyfile_data_from_file(py)?;
+
+        // check if encrypted
+        let is_encrypted = keyfile_data_is_encrypted(py, keyfile_data.extract(py)?)?;
+
+        Ok(is_encrypted)
+    }
+
+    /// Asks the user if it is okay to overwrite the file.
+    pub fn _may_overwrite(&self) -> bool {
+        let choice = utils::prompt(format!(
+            "File {} already exists. Overwrite? (y/N) ",
+            self.path
+        ))
+        .expect("Failed to read input.");
+
+        choice.trim().to_lowercase() == "y"
+    }
+
+    /// Check the version of keyfile and update if needed.
+    #[pyo3(signature = (print_result = true, no_prompt = false))]
+    pub fn check_and_update_encryption(
+        &self,
+        print_result: bool,
+        no_prompt: bool,
+        py: Python,
+    ) -> PyResult<bool> {
+        if !self.exists_on_device()? {
+            if print_result {
+                utils::print(format!("Keyfile does not exist. {}", self.path));
+            }
+            return Ok(false);
+        }
+
+        if !self.is_readable()? {
+            if print_result {
+                utils::print(format!("Keyfile is not readable. {}", self.path));
+            }
+            return Ok(false);
+        }
+
+        if !self.is_writable()? {
+            if print_result {
+                utils::print(format!("Keyfile is not writable. {}", self.path));
+            }
+            return Ok(false);
+        }
+
+        let update_keyfile = false;
+        if !no_prompt {
+            // read keyfile
+            let keyfile_data = self._read_keyfile_data_from_file(py)?;
+            let keyfile_data_bytes: &[u8] = keyfile_data.extract(py)?;
+
+            // check if file is decrypted
+            if keyfile_data_is_encrypted(py, keyfile_data_bytes)?
+                && !keyfile_data_is_encrypted_nacl(py, keyfile_data_bytes)?
+            {
+                utils::print("You may update the keyfile to improve security...".to_string());
+
+                // ask user for the confirmation for updating
+                if update_keyfile == confirm_prompt("Update keyfile?") {
+                    let mut stored_mnemonic = false;
+
+                    // check mnemonic if saved
+                    while !stored_mnemonic {
+                        utils::print(
+                            "Please store your mnemonic in case an error occurs...".to_string(),
+                        );
+                        if confirm_prompt("Have you stored the mnemonic?") {
+                            stored_mnemonic = true;
+                        } else if !confirm_prompt("Retry and continue keyfile update?") {
+                            return Ok(false);
+                        }
+                    }
+
+                    // try decrypt data
+                    let mut decrypted_keyfile_data: Option<Vec<u8>> = None;
+                    let mut password: Option<String> = None;
+                    while decrypted_keyfile_data.is_none() {
+                        let pwd = ask_password(py)?;
+                        password = Some(pwd.clone());
+
+                        match decrypt_keyfile_data(
+                            py,
+                            keyfile_data_bytes,
+                            Some(pwd),
+                            Some(self.name.clone()),
+                        ) {
+                            Ok(decrypted_data) => {
+                                let data: Vec<u8> = decrypted_data.extract(py)?;
+                                decrypted_keyfile_data = Some(data);
+                            }
+                            Err(_) => {
+                                if !confirm_prompt("Invalid password, retry?") {
+                                    return Ok(false);
+                                }
+                            }
+                        }
+                    }
+
+                    // encryption of updated data
+                    if let Some(password) = password {
+                        if let Some(decrypted_data) = decrypted_keyfile_data {
+                            let encrypted_keyfile_data =
+                                encrypt_keyfile_data(py, &decrypted_data, Some(password))?;
+                            self._write_keyfile_data_to_file(
+                                encrypted_keyfile_data.extract(py)?,
+                                true,
+                            )?;
+                        }
+                    }
+                }
+            }
+        }
+
+        if print_result || update_keyfile {
+            // check and get result
+            let keyfile_data = self._read_keyfile_data_from_file(py)?;
+            let keyfile_data_bytes: &[u8] = keyfile_data.extract(py)?;
+
+            return if !keyfile_data_is_encrypted(py, keyfile_data_bytes)? {
+                if print_result {
+                    utils::print("Keyfile is not encrypted.".to_string());
+                }
+                Ok(false)
+            } else if keyfile_data_is_encrypted_nacl(py, keyfile_data_bytes)? {
+                if print_result {
+                    utils::print("Keyfile is updated.".to_string());
+                }
+                Ok(true)
+            } else {
+                if print_result {
+                    utils::print("Keyfile is outdated, please update using 'btcli'.".to_string());
+                }
+                Ok(false)
+            };
+        }
+        Ok(false)
+    }
+
+    /// Encrypts the file under the path.
+    #[pyo3(signature = (password = None))]
+    pub fn encrypt(&self, password: Option<String>, py: Python) -> PyResult<()> {
+        // checkers
+        if !self.exists_on_device()? {
+            return Err(PyErr::new::<PyValueError, _>(format!(
+                "Keyfile at: {} does not exist",
+                self.path
+            )));
+        }
+
+        if !self.is_readable()? {
+            return Err(PyErr::new::<PyPermissionError, _>(format!(
+                "Keyfile at: {} is not readable",
+                self.path
+            )));
+        }
+
+        if !self.is_writable()? {
+            return Err(PyErr::new::<PyPermissionError, _>(format!(
+                "Keyfile at: {} is not writable",
+                self.path
+            )));
+        }
+
+        // read the data
+        let keyfile_data = self._read_keyfile_data_from_file(py)?;
+        let keyfile_data_bytes: &[u8] = keyfile_data.extract(py)?;
+
+        let final_data = if !keyfile_data_is_encrypted(py, keyfile_data_bytes)? {
+            let as_keypair = deserialize_keypair_from_keyfile_data(keyfile_data_bytes, py)?;
+            let serialized_data = serialized_keypair_to_keyfile_data(py, &as_keypair)?;
+
+            encrypt_keyfile_data(py, serialized_data.extract(py)?, password)?
+        } else {
+            keyfile_data
+        };
+
+        // write back
+        self._write_keyfile_data_to_file(final_data.extract(py)?, true)?;
+
+        Ok(())
+    }
+
+    /// Decrypts the file under the path.
+    #[pyo3(signature = (password = None))]
+    pub fn decrypt(&self, password: Option<String>, py: Python) -> PyResult<()> {
+        // checkers
+        if !self.exists_on_device()? {
+            return Err(PyErr::new::<PyOSError, _>(format!(
+                "Keyfile at: {} does not exist.",
+                self.path
+            )));
+        }
+        if !self.is_readable()? {
+            return Err(PyErr::new::<PyOSError, _>(format!(
+                "Keyfile at: {} is not readable.",
+                self.path
+            )));
+        }
+        if !self.is_writable()? {
+            return Err(PyErr::new::<PyOSError, _>(format!(
+                "Keyfile at: {} is not writable.",
+                self.path
+            )));
+        }
+
+        // read data
+        let keyfile_data = self._read_keyfile_data_from_file(py)?;
+        let keyfile_data_bytes: &[u8] = keyfile_data.extract(py)?;
+
+        let decrypted_data = if keyfile_data_is_encrypted(py, keyfile_data_bytes)? {
+            decrypt_keyfile_data(py, keyfile_data_bytes, password, Some(self.name.clone()))?
+        } else {
+            keyfile_data
+        };
+
+        let decrypted_bytes: &[u8] = decrypted_data.extract(py)?;
+        let as_keypair = deserialize_keypair_from_keyfile_data(decrypted_bytes, py)?;
+
+        let serialized_data = serialized_keypair_to_keyfile_data(py, &as_keypair)?;
+        self._write_keyfile_data_to_file(serialized_data.extract(py)?, true)?;
+        Ok(())
+    }
+
+    /// Reads the keyfile data from the file.
+    ///
+    ///     Returns:
+    ///         keyfile_data (bytes): The keyfile data stored under the path.
+    ///
+    ///     Raises:
+    ///         PyPermissionError: Raised if the file does not exist or is not readable.
+    pub fn _read_keyfile_data_from_file(&self, py: Python) -> PyResult<PyObject> {
+        // check file exist
+        if !self.exists_on_device()? {
+            return Err(PyErr::new::<PyFileNotFoundError, _>(format!(
+                "Keyfile at: {} does not exist.",
+                self.path
+            )));
+        }
+
+        // check if file readable
+        if !self.is_readable()? {
+            return Err(PyErr::new::<PyPermissionError, _>(format!(
+                "Keyfile at: {} is not readable.",
+                self.path
+            )));
+        }
+
+        // open and read the file
+        let mut file = fs::File::open(&self.path)
+            .map_err(|e| PyErr::new::<PyOSError, _>(format!("Failed to open file: {}.", e)))?;
+        let mut data_vec = Vec::new();
+        file.read_to_end(&mut data_vec)
+            .map_err(|e| PyErr::new::<PyOSError, _>(format!("Failed to read file: {}.", e)))?;
+
+        let data_bytes = PyBytes::new_bound(py, &data_vec).into_py(py);
+        Ok(data_bytes)
+    }
+
+    /// Writes the keyfile data to the file.
+    ///
+    ///     Arguments:
+    ///         keyfile_data (bytes): The byte data to store under the path.
+    ///         overwrite (bool, optional): If ``True``, overwrites the data without asking for permission from the user. Default is ``False``.
+    ///
+    ///     Raises:
+    ///         PyPermissionError: Raised if the file is not writable or the user responds No to the overwrite prompt.
+    #[pyo3(signature = (keyfile_data, overwrite = false))]
+    pub fn _write_keyfile_data_to_file(
+        &self,
+        keyfile_data: &[u8],
+        overwrite: bool,
+    ) -> PyResult<()> {
+        // ask user for rewriting
+        if self.exists_on_device()? && !overwrite && !self._may_overwrite() {
+            return Err(PyErr::new::<KeyFileError, _>(format!(
+                "Keyfile at: {} is not writable",
+                self.path
+            )));
+        }
+
+        let mut keyfile = fs::OpenOptions::new()
+            .write(true)
+            .create(true)
+            .truncate(true) // cleanup if rewrite
+            .open(&self.path)
+            .map_err(|e| PyErr::new::<PyIOError, _>(format!("Failed to open file: {}.", e)))?;
+
+        // write data
+        keyfile
+            .write_all(keyfile_data)
+            .map_err(|e| PyErr::new::<PyIOError, _>(format!("Failed to write to file: {}.", e)))?;
+
+        // set permissions
+        let mut permissions = fs::metadata(&self.path)?.permissions();
+        permissions.set_mode(0o600); // just for owner
+        fs::set_permissions(&self.path, permissions).map_err(|e| {
+            PyErr::new::<PyPermissionError, _>(format!("Failed to set permissions: {}.", e))
+        })?;
+        Ok(())
+    }
+}
diff --git a/src/keypair.rs b/src/keypair.rs
new file mode 100644
index 0000000..095f6de
--- /dev/null
+++ b/src/keypair.rs
@@ -0,0 +1,605 @@
+use pyo3::exceptions::{PyRuntimeError, PyTypeError, PyValueError};
+use pyo3::prelude::*;
+use pyo3::types::{PyBytes, PyString};
+use pyo3::PyObject;
+
+use crate::errors::ConfigurationError;
+use sp_core::crypto::Ss58Codec;
+use sp_core::{sr25519, ByteArray, Pair};
+
+use base64::{engine::general_purpose, Engine as _};
+use bip39::Mnemonic;
+use schnorrkel::{PublicKey, SecretKey};
+use scrypt::{scrypt, Params as ScryptParams};
+use serde::{Deserialize, Serialize};
+use sodiumoxide::crypto::secretbox;
+use sodiumoxide::crypto::secretbox::{Key, Nonce};
+
+const PKCS8_HEADER: &[u8] = &[48, 83, 2, 1, 1, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32];
+const PKCS8_DIVIDER: &[u8] = &[161, 35, 3, 33, 0];
+const SEC_LENGTH: usize = 64;
+const PUB_LENGTH: usize = 32;
+
+#[derive(Serialize, Deserialize, Debug)]
+struct Encoding {
+    content: Vec<String>,
+    #[serde(rename = "type")]
+    enc_type: Vec<String>,
+    version: String,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+struct Meta {
+    #[serde(rename = "genesisHash")]
+    genesis_hash: Option<String>,
+    name: String,
+    #[serde(rename = "whenCreated")]
+    when_created: u64,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+struct JsonStructure {
+    encoded: String,
+    encoding: Encoding,
+    address: String,
+    meta: Meta,
+}
+
+#[derive(Clone)]
+#[pyclass(subclass)]
+pub struct Keypair {
+    ss58_address: Option<String>,
+    public_key: Option<String>,
+    private_key: Option<String>,
+    ss58_format: u8,
+    seed_hex: Option<Vec<u8>>,
+    crypto_type: u8,
+    mnemonic: Option<String>,
+    pair: Option<sr25519::Pair>,
+}
+
+#[pymethods]
+impl Keypair {
+    #[new]
+    #[pyo3(signature = (ss58_address = None, public_key = None, private_key = None, ss58_format = 42, seed_hex = None, crypto_type = 1))]
+    pub fn new(
+        ss58_address: Option<String>,
+        public_key: Option<String>,
+        private_key: Option<String>,
+        ss58_format: u8,
+        seed_hex: Option<Vec<u8>>,
+        crypto_type: u8,
+    ) -> PyResult<Self> {
+        if crypto_type != 1 {
+            return Err(PyErr::new::<PyValueError, _>(format!(
+                "Unsupported crypto type: {}.",
+                crypto_type
+            )));
+        }
+
+        let mut ss58_address_res = ss58_address.clone();
+        let mut public_key_res = public_key;
+
+        if let Some(private_key_str) = &private_key {
+            let private_key_bytes =
+                hex::decode(private_key_str.trim_start_matches("0x")).expect("");
+
+            if private_key_bytes.len() != 64 {
+                return Err(PyErr::new::<PyValueError, _>(
+                    "Secret key should be 64 bytes long.",
+                ));
+            }
+
+            // TODO: add logic creation pair from private key
+        }
+
+        // if public_key is passed
+        if let Some(public_key_str) = &public_key_res {
+            let public_key_vec =
+                hex::decode(public_key_str.trim_start_matches("0x")).map_err(|e| {
+                    PyErr::new::<PyValueError, _>(format!("Invalid `public_key` string: {}", e))
+                })?;
+
+            let public_key_array: [u8; 32] = public_key_vec
+                .try_into()
+                .map_err(|_| PyErr::new::<PyValueError, _>("Public key must be 32 bytes long."))?;
+
+            let public_key = sr25519::Public::from_raw(public_key_array);
+
+            ss58_address_res = Option::from(public_key.to_ss58check());
+        }
+
+        // If ss58_address is passed, decode the public key
+        if let Some(ss58_address_str) = ss58_address.clone() {
+            let public_key = sr25519::Public::from_ss58check(&ss58_address_str).map_err(|e| {
+                PyErr::new::<ConfigurationError, _>(format!("Invalid SS58 address: {}", e))
+            })?;
+
+            public_key_res = Some(hex::encode(public_key.to_raw()));
+        }
+
+        let kp = Keypair {
+            ss58_address: ss58_address_res,
+            public_key: public_key_res,
+            private_key,
+            ss58_format,
+            seed_hex,
+            crypto_type,
+            mnemonic: None,
+            pair: None,
+        };
+
+        // If public_key is missing (ss58_address wasn't created), return an error
+        if kp.public_key.is_none() {
+            return Err(PyErr::new::<PyValueError, _>(
+                "No SS58 formatted address or public key provided.",
+            ));
+        }
+        Ok(kp)
+    }
+
+    fn __str__(&self) -> PyResult<String> {
+        match self.ss58_address()? {
+            Some(address) => Ok(format!("<Keypair (address={})>", address)),
+            None => Ok("<Keypair (address=None)>".to_string()),
+        }
+    }
+
+    fn __repr__(&self) -> PyResult<String> {
+        self.__str__()
+    }
+
+    /// Creates mnemonic from amount of words (accepted: 12, 15, 18, 21 or 24).
+    #[staticmethod]
+    #[pyo3(signature = (n_words = 12))]
+    pub fn generate_mnemonic(n_words: usize) -> PyResult<String> {
+        let mnemonic = Mnemonic::generate(n_words)
+            .map_err(|e| PyErr::new::<PyRuntimeError, _>(e.to_string()))?;
+        Ok(mnemonic.to_string())
+    }
+
+    /// Creates Keypair from a mnemonic.
+    #[staticmethod]
+    #[pyo3(signature = (mnemonic))]
+    pub fn create_from_mnemonic(mnemonic: &str) -> PyResult<Self> {
+        let (pair, seed_vec) = sr25519::Pair::from_phrase(mnemonic, None)
+            .map_err(|e| PyErr::new::<PyValueError, _>(e.to_string()))?;
+
+        let kp = Keypair {
+            mnemonic: Some(mnemonic.to_string()),
+            seed_hex: Some(seed_vec.to_vec()),
+            pair: Some(pair),
+            ..Default::default()
+        };
+        Ok(kp)
+    }
+
+    /// Creates Keypair from a seed for python
+    #[staticmethod]
+    #[pyo3(signature = (seed_hex))]
+    pub fn create_from_seed(seed_hex: &Bound<'_, PyAny>) -> PyResult<Self> {
+        Python::with_gil(|_py| {
+            let seed: Vec<u8>;
+
+            if seed_hex.is_instance_of::<PyString>() {
+                let seed_str: &str = seed_hex.extract()?;
+                seed = hex::decode(seed_str.trim_start_matches("0x")).map_err(|e| {
+                    PyErr::new::<PyValueError, _>(format!("Invalid hex string: {}", e))
+                })?;
+            } else if seed_hex.is_instance_of::<PyBytes>() {
+                seed = seed_hex.extract()?;
+            } else {
+                return Err(PyErr::new::<PyValueError, _>(
+                    "Unsupported seed format. Expected hex string or bytes.",
+                ));
+            }
+
+            let pair = sr25519::Pair::from_seed_slice(&seed).map_err(|e| {
+                PyErr::new::<PyValueError, _>(format!("Failed to create pair from seed: {}", e))
+            })?;
+
+            let kp = Keypair {
+                seed_hex: Some(seed.to_vec()),
+                pair: Some(pair),
+                ..Default::default()
+            };
+
+            // let kp = Keypair {
+            //     ..Default::default()
+            // };
+
+            Ok(kp)
+        })
+    }
+
+    /// Creates Keypair from `private key`.
+    #[staticmethod]
+    #[pyo3(signature = (private_key))]
+    pub fn create_from_private_key(private_key: &str) -> PyResult<Self> {
+        let private_key_vec = hex::decode(private_key.trim_start_matches("0x")).map_err(|e| {
+            PyErr::new::<ConfigurationError, _>(format!("Invalid `private_key` string: {}", e))
+        })?;
+
+        let pair = sr25519::Pair::from_seed_slice(&private_key_vec).map_err(|e| {
+            PyErr::new::<ConfigurationError, _>(format!(
+                "Failed to create pair from private key: {}",
+                e
+            ))
+        })?;
+
+        let kp = Keypair {
+            pair: Some(pair),
+            ..Default::default()
+        };
+        Ok(kp)
+    }
+
+    #[staticmethod]
+    #[pyo3(signature = (json_data, passphrase))]
+    pub fn create_from_encrypted_json(json_data: &str, passphrase: &str) -> PyResult<Keypair> {
+        /// rust version of python .rjust
+        fn pad_right(mut data: Vec<u8>, total_len: usize, pad_byte: u8) -> Vec<u8> {
+            if data.len() < total_len {
+                let pad_len = total_len - data.len();
+                data.extend(vec![pad_byte; pad_len]);
+            }
+            data
+        }
+
+        pub fn pair_from_ed25519_secret_key(secret: &[u8], pubkey: &[u8]) -> ([u8; 64], [u8; 32]) {
+            match (
+                SecretKey::from_ed25519_bytes(secret),
+                PublicKey::from_bytes(pubkey),
+            ) {
+                (Ok(s), Ok(k)) => (s.to_bytes(), k.to_bytes()),
+                _ => panic!("Invalid secret or pubkey provided."),
+            }
+        }
+
+        /// Decodes a PKCS8-encoded key pair from the provided byte slice.
+        /// Returns a tuple containing the private key and public key as vectors of bytes.
+        fn decode_pkcs8(
+            ciphertext: &[u8],
+        ) -> Result<([u8; SEC_LENGTH], [u8; PUB_LENGTH]), &'static str> {
+            let mut current_offset = 0;
+            let header = &ciphertext[current_offset..current_offset + PKCS8_HEADER.len()];
+            if header != PKCS8_HEADER {
+                return Err("Invalid Pkcs8 header found in body");
+            }
+            current_offset += PKCS8_HEADER.len();
+            let secret_key = &ciphertext[current_offset..current_offset + SEC_LENGTH];
+            let mut secret_key_array = [0u8; SEC_LENGTH];
+            secret_key_array.copy_from_slice(secret_key);
+            current_offset += SEC_LENGTH;
+            let divider = &ciphertext[current_offset..current_offset + PKCS8_DIVIDER.len()];
+            if divider != PKCS8_DIVIDER {
+                return Err("Invalid Pkcs8 divider found in body");
+            }
+            current_offset += PKCS8_DIVIDER.len();
+            let public_key = &ciphertext[current_offset..current_offset + PUB_LENGTH];
+            let mut public_key_array = [0u8; PUB_LENGTH];
+            public_key_array.copy_from_slice(public_key);
+            Ok((secret_key_array, public_key_array))
+        }
+
+        let json_data: JsonStructure = serde_json::from_str(json_data).unwrap();
+
+        if json_data.encoding.version != "3" {
+            return Err(PyErr::new::<PyValueError, _>("Unsupported JSON format"));
+        }
+
+        let mut encrypted = general_purpose::STANDARD
+            .decode(json_data.encoded)
+            .map_err(|e| PyErr::new::<PyValueError, _>(e.to_string()))?;
+
+        let password = if json_data.encoding.enc_type.contains(&"scrypt".to_string()) {
+            let salt = &encrypted[0..32];
+            let n = u32::from_le_bytes(encrypted[32..36].try_into()?);
+            let p = u32::from_le_bytes(encrypted[36..40].try_into()?);
+            let r = u32::from_le_bytes(encrypted[40..44].try_into()?);
+            let log_n: u8 = n.ilog2() as u8;
+
+            let params = ScryptParams::new(log_n, r, p, 32)
+                .map_err(|e| PyErr::new::<PyRuntimeError, _>(e.to_string()))?;
+            let mut derived_key = vec![0u8; 32];
+            scrypt(passphrase.as_bytes(), salt, &params, &mut derived_key)
+                .map_err(|e| PyErr::new::<PyValueError, _>(e.to_string()))?;
+            encrypted = encrypted[44..].to_vec();
+            derived_key
+        } else {
+            let mut derived_key = passphrase.as_bytes().to_vec();
+            derived_key = pad_right(derived_key, 32, 0x00);
+            derived_key
+        };
+
+        let nonce_bytes = &encrypted[0..24];
+        let nonce = Nonce::from_slice(nonce_bytes)
+            .ok_or("Invalid nonce length")
+            .map_err(|e| PyErr::new::<PyValueError, _>(e.to_string()))?;
+        let message = &encrypted[24..];
+
+        let key = Key::from_slice(&password)
+            .ok_or(PyErr::new::<PyValueError, _>("Invalid key length"))?;
+        let decrypted_data =
+            secretbox::open(message, &nonce, &key).map_err(PyErr::new::<PyValueError, _>)?;
+        let (private_key, public_key) =
+            decode_pkcs8(&decrypted_data).map_err(PyErr::new::<PyValueError, _>)?;
+
+        let (secret, converted_public_key) =
+            pair_from_ed25519_secret_key(&private_key[..], &public_key[..]);
+
+        let keypair = match json_data.encoding.content.iter().any(|c| c == "sr25519") {
+            true => {
+                assert_eq!(public_key, converted_public_key);
+                Keypair::create_from_private_key(&hex::encode(secret))
+            }
+            _ => return Err(PyErr::new::<PyValueError, _>("Unsupported keypair type.")),
+        };
+
+        keypair
+    }
+
+    /// Creates Keypair from create_from_uri as string.
+    #[staticmethod]
+    #[pyo3(signature = (uri))]
+    pub fn create_from_uri(uri: &str) -> PyResult<Self> {
+        let pair = Pair::from_string(uri, None)
+            .map_err(|e| PyErr::new::<PyValueError, _>(e.to_string()))?;
+
+        let kp = Keypair {
+            pair: Some(pair),
+            ..Default::default()
+        };
+        Ok(kp)
+    }
+
+    /// Creates a signature for given data.
+    #[pyo3(signature = (data))]
+    pub fn sign(&self, data: PyObject, py: Python) -> PyResult<PyObject> {
+        // Convert data to bytes (data can be a string, hex, or bytes)
+        let data_bytes = if let Ok(s) = data.extract::<String>(py) {
+            if s.starts_with("0x") {
+                hex::decode(s.trim_start_matches("0x")).map_err(|e| {
+                    PyErr::new::<ConfigurationError, _>(format!("Invalid hex string: {}", e))
+                })?
+            } else {
+                s.into_bytes()
+            }
+        } else if let Ok(bytes) = data.extract::<Vec<u8>>(py) {
+            bytes
+        } else if let Ok(py_scale_bytes) = data.extract::<&PyAny>(py) {
+            let scale_data: &PyAny = py_scale_bytes.getattr("data")?;
+            let scale_data_bytes: Vec<u8> = scale_data.extract()?;
+
+            scale_data_bytes.to_vec()
+        } else {
+            return Err(PyErr::new::<ConfigurationError, _>(
+                "Keypair::sign: Unsupported data format. Expected str or bytes.",
+            ));
+        };
+
+        // Check if private key is exist
+        let pair = self.pair.as_ref().ok_or_else(|| {
+            PyErr::new::<ConfigurationError, _>("No private key set to create signatures")
+        })?;
+
+        // Generate a signature depending on the type of cryptographic key
+        let signature = match self.crypto_type {
+            1 => {
+                // SR25519
+                pair.sign(&data_bytes)
+            }
+            _ => {
+                return Err(PyErr::new::<ConfigurationError, _>(
+                    "Crypto type not supported.",
+                ));
+            }
+        };
+
+        // Return the signature as a Python object (bytes)
+        Ok(PyBytes::new_bound(py, &signature).into_py(py))
+    }
+
+    // The same logic as in python version `substrateinterface.keypair.Keypair.verify`
+    /// Verifies data with specified signature.
+    #[pyo3(signature = (data, signature))]
+    pub fn verify(&self, data: PyObject, signature: PyObject, py: Python) -> PyResult<bool> {
+        // Convert data to bytes (data can be a string, hex, or bytes)
+        let data_bytes = if let Ok(s) = data.extract::<String>(py) {
+            if s.starts_with("0x") {
+                hex::decode(s.trim_start_matches("0x")).map_err(|e| {
+                    PyErr::new::<PyValueError, _>(format!("Invalid hex string: {:?}", e))
+                })?
+            } else {
+                s.into_bytes()
+            }
+        } else if let Ok(bytes) = data.extract::<Vec<u8>>(py) {
+            bytes
+        } else if let Ok(py_scale_bytes) = data.extract::<&PyAny>(py) {
+            let scale_data: &PyAny = py_scale_bytes.getattr("data")?;
+            let scale_data_bytes: Vec<u8> = scale_data.extract()?;
+
+            scale_data_bytes.to_vec()
+        } else {
+            return Err(PyErr::new::<ConfigurationError, _>(
+                "Keypair::verify: Unsupported data format. Expected str or bytes.",
+            ));
+        };
+        // TODO: implement the ability to process data as ScaleBytes object
+
+        // Convert signature to bytes
+        let signature_bytes = if let Ok(s) = signature.extract::<String>(py) {
+            if s.starts_with("0x") {
+                hex::decode(s.trim_start_matches("0x")).map_err(|e| {
+                    PyErr::new::<PyValueError, _>(format!("Invalid hex string: {:?}", e))
+                })?
+            } else {
+                return Err(PyErr::new::<PyValueError, _>(
+                    "Invalid signature format. Expected hex string.",
+                ));
+            }
+        } else if let Ok(bytes) = signature.extract::<Vec<u8>>(py) {
+            bytes
+        } else {
+            return Err(PyErr::new::<PyTypeError, _>(
+                "Unsupported signature format. Expected str or bytes.",
+            ));
+        };
+
+        // Check if public key is exist
+        let public_key = if let Some(public_key_str) = &self.public_key {
+            hex::decode(public_key_str.trim_start_matches("0x")).map_err(|e| {
+                PyErr::new::<ConfigurationError, _>(format!("Invalid `public_key` string: {:?}", e))
+            })?
+        } else if let Some(pair) = &self.pair {
+            pair.public().to_vec()
+        } else {
+            return Err(PyErr::new::<ConfigurationError, _>(
+                "No public key or pair available.",
+            ));
+        };
+
+        let public = sr25519::Public::from_raw(<[u8; 32]>::try_from(public_key).map_err(|e| {
+            PyErr::new::<ConfigurationError, _>(format!("Invalid public key length: {:?}", e))
+        })?);
+
+        // Convert signature bytes to the type expected by the verify function
+        let signature = sr25519::Signature::from_slice(&signature_bytes)
+            .map_err(|_| PyErr::new::<PyValueError, _>("Invalid signature"))?;
+        // Verify signature depending on the type of crypto key
+        let verified = match self.crypto_type {
+            1 => {
+                // SR25519
+                sr25519::Pair::verify(&signature, &data_bytes, &public)
+            }
+            _ => {
+                return Err(PyErr::new::<ConfigurationError, _>(
+                    "Crypto type not supported",
+                ));
+            }
+        };
+
+        // If not verified, try to verify with data wrapper
+        if !verified {
+            let wrapped_data = [b"<Bytes>", data_bytes.as_slice(), b"</Bytes>"].concat();
+            let verified_wrapped = match self.crypto_type {
+                1 => {
+                    // SR25519
+                    sr25519::Pair::verify(&signature, wrapped_data, &public)
+                }
+                _ => {
+                    return Err(PyErr::new::<ConfigurationError, _>(
+                        "Crypto type not supported",
+                    ));
+                }
+            };
+
+            Ok(verified_wrapped)
+        } else {
+            Ok(verified)
+        }
+    }
+    /// Returns the SS58 address.
+    #[getter]
+    pub fn ss58_address(&self) -> PyResult<Option<String>> {
+        match &self.pair {
+            Some(pair) => {
+                let ss58_address = pair.public().to_ss58check();
+                Ok(Some(ss58_address))
+            }
+            None => {
+                if self.ss58_address.is_none() {
+                    Ok(None)
+                } else {
+                    Ok(self.ss58_address.clone())
+                }
+            }
+        }
+    }
+
+    /// Returns the public key as a bytes.
+    #[getter]
+    pub fn public_key(&self, py: Python) -> PyResult<Option<PyObject>> {
+        if let Some(pair) = &self.pair {
+            let public_key_vec = pair.public().to_vec();
+            Ok(Some(PyBytes::new_bound(py, &public_key_vec).into_py(py)))
+        } else if let Some(public_key) = &self.public_key {
+            let public_key_vec = hex::decode(public_key.trim_start_matches("0x")).map_err(|e| {
+                PyErr::new::<PyValueError, _>(format!("Invalid `public_key` string: {}", e))
+            })?;
+            Ok(Some(PyBytes::new_bound(py, &public_key_vec).into_py(py)))
+        } else {
+            Ok(None)
+        }
+    }
+
+    /// Returns the ss58_format as integer.
+    #[getter]
+    pub fn ss58_format(&self) -> PyResult<u8> {
+        Ok(self.ss58_format)
+    }
+
+    /// Returns seed_hex as bytes.
+    #[getter]
+    pub fn seed_hex(&self, py: Python) -> PyResult<Option<PyObject>> {
+        match &self.seed_hex {
+            Some(seed_hex) => Ok(Some(PyBytes::new_bound(py, seed_hex).into_py(py))),
+            None => Ok(None),
+        }
+    }
+
+    /// Returns crypto_type key as an int.
+    #[getter]
+    pub fn crypto_type(&self) -> PyResult<u8> {
+        Ok(self.crypto_type)
+    }
+
+    /// Returns mnemonic key as a string.
+    #[getter]
+    pub fn mnemonic(&self) -> PyResult<Option<String>> {
+        if self.mnemonic.is_none() {
+            Ok(None)
+        } else {
+            Ok(self.mnemonic.clone())
+        }
+    }
+}
+
+impl Keypair {
+    /// Returns the private key as a bytes for internal usage.
+    pub fn private_key(&self, py: Python) -> PyResult<Option<PyObject>> {
+        match &self.pair {
+            Some(pair) => {
+                let seed = pair.to_raw_vec();
+                Ok(Some(PyBytes::new_bound(py, &seed).into_py(py)))
+            }
+            None => {
+                if self.private_key.is_none() {
+                    Ok(None)
+                } else {
+                    Ok(Some(
+                        PyBytes::new_bound(py, self.private_key.as_ref().unwrap().as_bytes())
+                            .into_py(py),
+                    ))
+                }
+            }
+        }
+    }
+}
+
+
+// Default values for Keypair
+impl Default for Keypair {
+    fn default() -> Self {
+        Keypair {
+            ss58_address: None,
+            public_key: None,
+            private_key: None,
+            ss58_format: 42,
+            seed_hex: None,
+            crypto_type: 1,
+            mnemonic: None,
+            pair: None,
+        }
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..4a90cab
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,134 @@
+/// Main module for declaration of python package structure
+use pyo3::prelude::*;
+
+mod config;
+mod constants;
+mod errors;
+mod keyfile;
+mod keypair;
+mod utils;
+mod wallet;
+
+#[pymodule]
+fn bittensor_wallet(module: &Bound<'_, PyModule>) -> PyResult<()> {
+    // classes to main module
+    module.add_class::<config::Config>()?;
+    module.add_class::<keyfile::Keyfile>()?;
+    module.add_class::<keypair::Keypair>()?;
+    module.add_class::<wallet::Wallet>()?;
+    // submodules to main module
+    register_config_module(module)?;
+    register_errors_module(module)?;
+    register_keyfile_module(module)?;
+    register_keypair_module(module)?;
+    register_utils_module(module)?;
+    register_wallet_module(module)?;
+    Ok(())
+}
+
+fn register_config_module(main_module: &Bound<'_, PyModule>) -> PyResult<()> {
+    let config_module = PyModule::new_bound(main_module.py(), "config")?;
+    config_module.add_class::<config::Config>()?;
+    main_module.add_submodule(&config_module)
+}
+
+fn register_errors_module(main_module: &Bound<'_, PyModule>) -> PyResult<()> {
+    let errors_module = PyModule::new_bound(main_module.py(), "errors")?;
+    errors_module.add_class::<errors::ConfigurationError>()?;
+    errors_module.add_class::<errors::KeyFileError>()?;
+    main_module.add_submodule(&errors_module)
+}
+
+// keyfile module with functions
+fn register_keyfile_module(main_module: &Bound<'_, PyModule>) -> PyResult<()> {
+    let keyfile_module = PyModule::new_bound(main_module.py(), "keyfile")?;
+    keyfile_module.add_function(wrap_pyfunction!(
+        keyfile::serialized_keypair_to_keyfile_data,
+        &keyfile_module
+    )?)?;
+    keyfile_module.add_function(wrap_pyfunction!(
+        keyfile::deserialize_keypair_from_keyfile_data,
+        &keyfile_module
+    )?)?;
+    keyfile_module.add_function(wrap_pyfunction!(
+        keyfile::validate_password,
+        &keyfile_module
+    )?)?;
+    keyfile_module.add_function(wrap_pyfunction!(keyfile::ask_password, &keyfile_module)?)?;
+    keyfile_module.add_function(wrap_pyfunction!(
+        keyfile::keyfile_data_is_encrypted_nacl,
+        &keyfile_module
+    )?)?;
+    keyfile_module.add_function(wrap_pyfunction!(
+        keyfile::keyfile_data_is_encrypted_ansible,
+        &keyfile_module
+    )?)?;
+    keyfile_module.add_function(wrap_pyfunction!(
+        keyfile::keyfile_data_is_encrypted_legacy,
+        &keyfile_module
+    )?)?;
+    keyfile_module.add_function(wrap_pyfunction!(
+        keyfile::keyfile_data_is_encrypted,
+        &keyfile_module
+    )?)?;
+    keyfile_module.add_function(wrap_pyfunction!(
+        keyfile::keyfile_data_encryption_method,
+        &keyfile_module
+    )?)?;
+    keyfile_module.add_function(wrap_pyfunction!(
+        keyfile::legacy_encrypt_keyfile_data,
+        &keyfile_module
+    )?)?;
+    keyfile_module.add_function(wrap_pyfunction!(
+        keyfile::get_coldkey_password_from_environment,
+        &keyfile_module
+    )?)?;
+    keyfile_module.add_function(wrap_pyfunction!(
+        keyfile::encrypt_keyfile_data,
+        &keyfile_module
+    )?)?;
+    keyfile_module.add_function(wrap_pyfunction!(
+        keyfile::decrypt_keyfile_data,
+        &keyfile_module
+    )?)?;
+    keyfile_module.add_class::<keyfile::Keyfile>()?;
+    main_module.add_submodule(&keyfile_module)
+}
+
+// keypair module with functions
+fn register_keypair_module(main_module: &Bound<'_, PyModule>) -> PyResult<()> {
+    let keypair_module = PyModule::new_bound(main_module.py(), "keypair")?;
+    keypair_module.add_class::<keypair::Keypair>()?;
+    main_module.add_submodule(&keypair_module)
+}
+
+// utils module with functions
+fn register_utils_module(main_module: &Bound<'_, PyModule>) -> PyResult<()> {
+    let utils_module = PyModule::new_bound(main_module.py(), "utils")?;
+    utils_module.add_function(wrap_pyfunction!(utils::get_ss58_format, &utils_module)?)?;
+    utils_module.add_function(wrap_pyfunction!(
+        utils::is_valid_ss58_address,
+        &utils_module
+    )?)?;
+    utils_module.add_function(wrap_pyfunction!(
+        utils::is_valid_ed25519_pubkey,
+        &utils_module
+    )?)?;
+    utils_module.add_function(wrap_pyfunction!(
+        utils::is_valid_bittensor_address_or_public_key,
+        &utils_module
+    )?)?;
+    utils_module.add("SS58_FORMAT", utils::SS58_FORMAT)?;
+    main_module.add_submodule(&utils_module)
+}
+
+// wallet module with functions
+fn register_wallet_module(main_module: &Bound<'_, PyModule>) -> PyResult<()> {
+    let wallet_module = PyModule::new_bound(main_module.py(), "wallet")?;
+    wallet_module.add_function(wrap_pyfunction!(
+        wallet::display_mnemonic_msg,
+        &wallet_module
+    )?)?;
+    wallet_module.add_class::<wallet::Wallet>()?;
+    main_module.add_submodule(&wallet_module)
+}
diff --git a/src/utils.rs b/src/utils.rs
new file mode 100644
index 0000000..5d1aea2
--- /dev/null
+++ b/src/utils.rs
@@ -0,0 +1,191 @@
+use pyo3::exceptions::PyValueError;
+use pyo3::prelude::*;
+use pyo3::types::{IntoPyDict, PyBytes, PyDict, PyString};
+
+use sp_core::crypto::{AccountId32, Ss58Codec};
+use std::str;
+
+use crate::keypair::Keypair;
+
+pub(crate) const SS58_FORMAT: u8 = 42;
+
+/// Returns the SS58 format of the given address string.
+#[pyfunction]
+pub fn get_ss58_format(ss58_address: &str) -> PyResult<u16> {
+    match <AccountId32 as Ss58Codec>::from_ss58check_with_version(ss58_address) {
+        Ok((_, format)) => Ok(u16::from(format)),
+        Err(_) => Err(PyErr::new::<PyValueError, _>("Invalid SS58 address.")),
+    }
+}
+
+/// Checks if the given address is a valid ss58 address.
+///
+/// Args:
+///     address(str): The address to check.
+///
+/// Returns:
+///     True if the address is a valid ss58 address for Bittensor, False otherwise.
+#[pyfunction]
+pub fn is_valid_ss58_address(address: &str) -> PyResult<bool> {
+    if address.is_empty() {
+        // Possibly there could be a debug log, but not a print
+        // utils::print(format!("The given address is empty"));
+        return Ok(false);
+    }
+
+    match sp_core::sr25519::Public::from_ss58check(address) {
+        Ok(_) => Ok(true),
+        Err(_) => {
+            // Possibly there could be a debug log, but not a print
+            // utils::print(format!("Invalid SS58 address format"));
+            Ok(false)
+        }
+    }
+}
+
+///    Checks if the given public_key is a valid ed25519 key.
+///
+///     Args:
+///         public_key(Union[str, bytes]): The public_key to check.
+///
+///     Returns:
+///         True if the public_key is a valid ed25519 key, False otherwise.
+#[pyfunction]
+pub fn is_valid_ed25519_pubkey(public_key: &Bound<'_, PyAny>) -> PyResult<bool> {
+    Python::with_gil(|_py| {
+        if public_key.is_instance_of::<PyString>() {
+            let pub_key_string: &str = public_key.extract()?;
+            if pub_key_string.len() != 64 && pub_key_string.len() != 66 {
+                // Possibly need to log the error for debug (a public_key should be 64 or 66 characters)
+                return Ok(false);
+            }
+        } else if public_key.is_instance_of::<PyBytes>() {
+            let pub_key_bytes: &[u8] = public_key.extract()?;
+            if pub_key_bytes.len() != 32 {
+                // Possibly need to log the error for debug (a public_key should be 32 bytes)
+                return Ok(false);
+            }
+        } else {
+            // Possibly need to log the error for debug (public_key must be a string or bytes)
+            return Ok(false);
+        }
+
+        let pub_key_var = Some(public_key.to_string());
+
+        let keypair_result = Keypair::new(None, pub_key_var, None, SS58_FORMAT, None, 1);
+
+        match keypair_result {
+            Ok(keypair) => {
+                if keypair.ss58_address()?.is_some() {
+                    return Ok(true);
+                }
+                Ok(false)
+            }
+            Err(_) => Ok(false),
+        }
+    })
+}
+
+///    Checks if the given address is a valid destination address.
+///
+///     Args:
+///         address(Union[str, bytes]): The address to check.
+///
+///     Returns:
+///         True if the address is a valid destination address, False otherwise.
+#[pyfunction]
+pub fn is_valid_bittensor_address_or_public_key(address: &Bound<'_, PyAny>) -> PyResult<bool> {
+    Python::with_gil(|_py| {
+        if address.is_instance_of::<PyString>() {
+            let address_str = &address.to_string();
+            if address_str.starts_with("0x") {
+                is_valid_ed25519_pubkey(address)
+            } else {
+                is_valid_ss58_address(address_str)
+            }
+        } else if address.is_instance_of::<PyBytes>() {
+            is_valid_ed25519_pubkey(address)
+        } else {
+            Ok(false)
+        }
+    })
+}
+
+pub fn print(s: String) {
+    Python::with_gil(|py| {
+        let locals = PyDict::new_bound(py);
+        locals.set_item("s", s).unwrap();
+        py.run_bound("print(s, end='')", None, Some(&locals))
+            .unwrap();
+    });
+}
+
+/// Prompts the user and returns the response, if any.
+///    
+/// Args:
+///     prompt: String
+///
+/// Returns:
+///     response: Option<&str>
+pub fn prompt(prompt: String) -> Option<String> {
+    let result: Result<String, ()> = Python::with_gil(|py| {
+        let result = py
+            .eval_bound(&format!("input(\"{}\")", prompt), None, None)
+            .map_err(|e| {
+                e.print_and_set_sys_last_vars(py);
+            })?;
+        result.extract::<String>().map_err(|e| {
+            e.print_and_set_sys_last_vars(py);
+        })
+    });
+
+    result.ok()
+}
+
+/// Prompts the user with a password entry and returns the response, if any.
+///    
+/// Args:
+///     prompt (String): the prompt to ask the user with.
+///
+/// Returns:
+///     response: Option<String>
+pub fn prompt_password(prompt: String) -> Option<String> {
+    let result: Result<String, ()> = Python::with_gil(|py| {
+        let locals = [(
+            "getpass",
+            py.import_bound("getpass").map_err(|e| {
+                e.print_and_set_sys_last_vars(py);
+            })?,
+        )]
+        .into_py_dict_bound(py);
+        let result = py
+            .eval_bound(
+                &format!("getpass.getpass(\"{}\")", prompt),
+                None,
+                Some(&locals),
+            )
+            .map_err(|e| {
+                e.print_and_set_sys_last_vars(py);
+            })?;
+        result.extract::<String>().map_err(|e| {
+            e.print_and_set_sys_last_vars(py);
+        })
+    });
+
+    let password = result.unwrap();
+    Some(password.trim().to_string())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_get_ss58_format_success() {
+        let test_address = "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty";
+        match is_valid_ss58_address(test_address) {
+            Ok(result) => assert_eq!(result, true),
+            Err(err) => panic!("Test failed with error: {:?}", err),
+        }
+    }
+}
diff --git a/src/wallet.rs b/src/wallet.rs
new file mode 100644
index 0000000..6537123
--- /dev/null
+++ b/src/wallet.rs
@@ -0,0 +1,666 @@
+use pyo3::exceptions::PyValueError;
+use pyo3::prelude::*;
+use pyo3::types::{IntoPyDict, PyString, PyType};
+
+use colored::Colorize;
+use std::env;
+
+use crate::config::Config;
+use crate::constants::{BT_WALLET_HOTKEY, BT_WALLET_NAME, BT_WALLET_PATH};
+use crate::errors::KeyFileError;
+use crate::keyfile::Keyfile;
+use crate::keypair::Keypair;
+use crate::utils::{self, is_valid_bittensor_address_or_public_key};
+
+use dirs::home_dir;
+
+type PyRuntimeError = KeyFileError;
+
+/// Display the mnemonic and a warning message to keep the mnemonic safe.
+#[pyfunction]
+#[pyo3(signature = (mnemonic, key_type))]
+pub fn display_mnemonic_msg(mnemonic: String, key_type: &str) {
+    utils::print(format!("{}", "\nIMPORTANT: Store this mnemonic in a secure (preferable offline place), as anyone who has possession of this mnemonic can use it to regenerate the key and access your tokens.".red()));
+
+    utils::print(format!(
+        "\nThe mnemonic to the new {} is: {}",
+        key_type.blue(),
+        mnemonic.green()
+    ));
+    utils::print(format!(
+        "\nYou can use the mnemonic to recreate the key with `{}` in case it gets lost.\n",
+        "btcli".green()
+    ));
+}
+
+#[derive(Clone)]
+#[pyclass(subclass)]
+pub struct Wallet {
+    pub name: String,
+    pub path: String,
+    pub hotkey: String,
+    pub config: Option<Config>,
+
+    _coldkey: Option<Keypair>,
+    _coldkeypub: Option<Keypair>,
+    _hotkey: Option<Keypair>,
+}
+
+#[pymethods]
+impl Wallet {
+    /// Initialize the bittensor wallet object containing a hot and coldkey.
+    ///
+    ///     Args:
+    ///         name (str, optional): The name of the wallet to unlock for running bittensor. Defaults to ``default``.
+    ///         hotkey (str, optional): The name of hotkey used to running the miner. Defaults to ``default``.
+    ///         path (str, optional): The path to your bittensor wallets. Defaults to ``~/.bittensor/wallets/``.
+    ///         config (Config, optional): config.Config(). Defaults to ``None``.
+    #[new]
+    #[pyo3(signature = (name = None, hotkey = None, path = None, config = None))]
+    fn new(
+        name: Option<String>,
+        hotkey: Option<String>,
+        path: Option<String>,
+        config: Option<Config>,
+    ) -> PyResult<Wallet> {
+        let final_name = name
+            .or_else(|| Some(config.clone()?.wallet.name.clone()))
+            .unwrap_or_else(|| BT_WALLET_NAME.to_string());
+        let final_hotkey = hotkey
+            .or_else(|| Some(config.clone()?.wallet.hotkey.clone()))
+            .unwrap_or_else(|| BT_WALLET_HOTKEY.to_string());
+        let final_path = path
+            .or_else(|| Some(config.clone()?.wallet.path.clone()))
+            .unwrap_or_else(|| BT_WALLET_PATH.to_string());
+
+        Ok(Wallet {
+            name: final_name,
+            hotkey: final_hotkey,
+            path: final_path,
+            config: config.or(None),
+            _coldkey: None,
+            _coldkeypub: None,
+            _hotkey: None,
+        })
+    }
+
+    fn __str__(&self) -> PyResult<String> {
+        Ok(format!(
+            "Wallet (Name: '{:}', Hotkey: '{:}', Path: '~/{:}')",
+            self.name, self.hotkey, self.path
+        ))
+    }
+
+    fn __repr__(&self) -> PyResult<String> {
+        Ok(format!(
+            "name: '{:}', hotkey: '{:}', path: '~/{:}'",
+            self.name, self.hotkey, self.path
+        ))
+    }
+
+    /// Get config from the argument parser.
+    #[classmethod]
+    pub fn config(_: &Bound<'_, PyType>) -> PyResult<Config> {
+        Config::new(None, None, None)
+    }
+
+    /// Print help to stdout.
+    #[classmethod]
+    pub fn help(_: &Bound<'_, PyType>) -> PyResult<Config> {
+        unimplemented!()
+    }
+
+    /// Accept specific arguments from parser.
+    #[classmethod]
+    #[pyo3(signature = (parser, prefix = None))]
+    pub fn add_args(
+        _: &Bound<'_, PyType>,
+        parser: &Bound<'_, PyAny>,
+        prefix: Option<String>,
+        py: Python,
+    ) -> PyResult<PyObject> {
+        let default_name =
+            env::var("BT_WALLET_NAME").unwrap_or_else(|_| BT_WALLET_NAME.to_string());
+        let default_hotkey =
+            env::var("BT_WALLET_HOTKEY").unwrap_or_else(|_| BT_WALLET_HOTKEY.to_string());
+        let default_path =
+            env::var("BT_WALLET_PATH").unwrap_or_else(|_| BT_WALLET_PATH.to_string());
+
+        let prefix_str = if let Some(value) = prefix {
+            format!("\"{}\"", value)
+        } else {
+            "None".to_string()
+        };
+
+        let code = format!(
+            r#"
+prefix = {}
+prefix_str = "" if prefix is None else prefix + "."
+
+try:
+    parser.add_argument(
+        "--" + prefix_str + "wallet.name",
+        required=False,
+        default="{}",
+        help="The name of the wallet to unlock for running bittensor "
+        "(name mock is reserved for mocking this wallet)",
+    )
+    parser.add_argument(
+        "--" + prefix_str + "wallet.hotkey",
+        required=False,
+        default="{}",
+        help="The name of the wallet's hotkey.",
+    )
+    parser.add_argument(
+        "--" + prefix_str + "wallet.path",
+        required=False,
+        default="{}",
+        help="The path to your bittensor wallets",
+    )
+except argparse.ArgumentError:
+    pass"#,
+            prefix_str, default_name, default_hotkey, default_path
+        );
+
+        py.run_bound(
+            &code,
+            Some(&[("parser", parser)].into_py_dict_bound(py)),
+            None,
+        )
+        .expect("Python parser parse failed.");
+        Ok(parser.to_object(py))
+    }
+
+    /// Checks for existing coldkeypub and hotkeys, and creates them if non-existent.
+    #[pyo3(signature = (coldkey_use_password=true, hotkey_use_password=false))]
+    pub fn create_if_non_existent(
+        &mut self,
+        coldkey_use_password: bool,
+        hotkey_use_password: bool,
+        py: Python,
+    ) -> PyResult<Wallet> {
+        self.create(coldkey_use_password, hotkey_use_password, py)
+    }
+
+    /// Checks for existing coldkeypub and hotkeys, and creates them if non-existent.
+    #[allow(clippy::bool_comparison)]
+    #[pyo3(signature = (coldkey_use_password=true, hotkey_use_password=false))]
+    pub fn create(
+        &mut self,
+        coldkey_use_password: bool,
+        hotkey_use_password: bool,
+        py: Python,
+    ) -> PyResult<Self> {
+        if self.coldkey_file()?.exists_on_device()? == false
+            && self.coldkeypub_file()?.exists_on_device()? == false
+        {
+            self.create_new_coldkey(12, coldkey_use_password, false, false, py)?;
+        } else {
+            utils::print(format!(
+                "ColdKey for the wallet '{}' already exists.",
+                self.name
+            ));
+        }
+
+        if !self.hotkey_file()?.exists_on_device()? {
+            self.create_new_hotkey(12, hotkey_use_password, false, false, py)?;
+        } else {
+            utils::print(format!(
+                "HotKey for the wallet '{}' already exists.",
+                self.name
+            ));
+        }
+
+        Ok(self.clone())
+    }
+
+    /// Checks for existing coldkeypub and hotkeys and creates them if non-existent.
+    #[pyo3(signature = (coldkey_use_password=true, hotkey_use_password=false))]
+    pub fn recreate(
+        &mut self,
+        coldkey_use_password: bool,
+        hotkey_use_password: bool,
+        py: Python,
+    ) -> PyResult<Wallet> {
+        self.create_new_coldkey(12, coldkey_use_password, false, false, py)?;
+        self.create_new_hotkey(12, hotkey_use_password, false, false, py)?;
+
+        Ok(self.clone())
+    }
+
+    /// Property that returns the hotkey file.
+    #[getter]
+    pub fn hotkey_file(&self) -> PyResult<Keyfile> {
+        // get home dir
+        let home = home_dir()
+            .ok_or_else(|| PyErr::new::<PyRuntimeError, _>("Failed to get user home directory."))?;
+
+        // concatenate wallet path
+        let wallet_path = home.join(&self.path).join(&self.name);
+
+        // concatenate hotkey path
+        let hotkey_path = wallet_path.join("hotkeys").join(&self.hotkey);
+
+        Keyfile::new(
+            hotkey_path.to_string_lossy().into_owned(),
+            Some(self.name.clone()),
+        )
+    }
+
+    /// Property that returns the coldkey file.
+    #[getter]
+    pub fn coldkey_file(&self) -> PyResult<Keyfile> {
+        // get home dir
+        let home = home_dir()
+            .ok_or_else(|| PyErr::new::<PyRuntimeError, _>("Failed to get user home directory."))?;
+
+        // concatenate wallet path
+        let wallet_path = home.join(&self.path).join(&self.name);
+
+        // concatenate coldkey path
+        let coldkey_path = wallet_path.join("coldkey");
+
+        Keyfile::new(
+            coldkey_path.to_string_lossy().into_owned(),
+            Some(self.name.clone()),
+        )
+    }
+
+    /// Property that returns the coldkeypub file.
+    #[getter]
+    pub fn coldkeypub_file(&self) -> PyResult<Keyfile> {
+        // get home dir
+        let home = home_dir()
+            .ok_or_else(|| PyErr::new::<PyRuntimeError, _>("Failed to get user home directory."))?;
+
+        // concatenate wallet path
+        let wallet_path = home.join(&self.path).join(&self.name);
+
+        // concatenate hotkey path
+        let coldkeypub_path = wallet_path.join("coldkeypub.txt");
+
+        Keyfile::new(
+            coldkeypub_path.to_string_lossy().into_owned(),
+            Some(self.name.clone()),
+        )
+    }
+
+    /// Loads the coldkey from wallet.path/wallet.name/coldkey or raises an error.
+    #[getter(coldkey)]
+    pub fn coldkey_py_property(&self, py: Python) -> PyResult<Keypair> {
+        if let Some(coldkey) = &self._coldkey {
+            Ok(coldkey.clone())
+        } else {
+            self.get_coldkey(None, py)
+        }
+    }
+
+    /// Loads the coldkeypub from wallet.path/wallet.name/coldkeypub.txt or raises an error.
+    #[getter(coldkeypub)]
+    pub fn coldkeypub_py_property(&self, py: Python) -> PyResult<Keypair> {
+        self.get_coldkeypub(None, py)
+    }
+
+    /// Loads the hotkey from wallet.path/wallet.name/hotkeys/wallet.hotkey or raises an error.
+    #[getter(hotkey)]
+    pub fn hotkey_py_property(&self, py: Python) -> PyResult<Keypair> {
+        if let Some(hotkey) = &self._hotkey {
+            Ok(hotkey.clone())
+        } else {
+            self.get_hotkey(None, py)
+        }
+    }
+
+    /// Loads the name from wallet.path/wallet.name/coldkeypub.txt or raises an error.
+    #[getter(name)]
+    pub fn get_name(&self) -> PyResult<String> {
+        Ok(self.name.clone())
+    }
+
+    /// Loads the name from wallet.path/wallet.name/coldkeypub.txt or raises an error.
+    #[getter(path)]
+    pub fn get_path(&self) -> PyResult<String> {
+        Ok(self.path.clone())
+    }
+
+    /// Loads the name from wallet.path/wallet.name/coldkeypub.txt or raises an error.
+    #[getter(hotkey_str)]
+    pub fn get_hotkey_str(&self) -> PyResult<String> {
+        Ok(self.hotkey.clone())
+    }
+
+    /// Sets the hotkey for the wallet.
+    #[pyo3(signature = (keypair, encrypt=true, overwrite=false))]
+    pub fn set_coldkey(
+        &mut self,
+        keypair: Keypair,
+        encrypt: bool,
+        overwrite: bool,
+        py: Python,
+    ) -> PyResult<()> {
+        self._coldkey = Some(keypair.clone());
+        self.coldkey_file()?
+            .set_keypair(keypair, encrypt, overwrite, None, py)
+    }
+
+    /// Sets the coldkeypub for the wallet.
+    #[pyo3(signature = (keypair, encrypt=false, overwrite=false))]
+    pub fn set_coldkeypub(
+        &mut self,
+        keypair: Keypair,
+        encrypt: bool,
+        overwrite: bool,
+        py: Python,
+    ) -> PyResult<()> {
+        let _ss58_address = keypair.ss58_address()?.unwrap();
+        let _coldkeypub_keypair = Keypair::new(Some(_ss58_address), None, None, 42, None, 1)?;
+
+        self._coldkeypub = Some(_coldkeypub_keypair.clone());
+        self.coldkeypub_file()?.set_keypair(
+            _coldkeypub_keypair.clone(),
+            encrypt,
+            overwrite,
+            None,
+            py,
+        )
+    }
+
+    /// Sets the hotkey for the wallet.
+    #[pyo3(signature = (keypair, encrypt=false, overwrite=false))]
+    pub fn set_hotkey(
+        &mut self,
+        keypair: Keypair,
+        encrypt: bool,
+        overwrite: bool,
+        py: Python,
+    ) -> PyResult<()> {
+        self._hotkey = Some(keypair.clone());
+        self.hotkey_file()?
+            .set_keypair(keypair.clone(), encrypt, overwrite, None, py)
+    }
+
+    /// Gets the coldkey from the wallet.
+    #[pyo3(signature = (password = None))]
+    pub fn get_coldkey(&self, password: Option<String>, py: Python) -> PyResult<Keypair> {
+        self.coldkey_file()?.get_keypair(password, py)
+    }
+
+    /// Gets the coldkeypub from the wallet.
+    #[pyo3(signature = (password = None))]
+    pub fn get_coldkeypub(&self, password: Option<String>, py: Python) -> PyResult<Keypair> {
+        self.coldkeypub_file()?.get_keypair(password, py)
+    }
+
+    /// Gets the hotkey from the wallet.
+    #[pyo3(signature = (password = None))]
+    pub fn get_hotkey(&self, password: Option<String>, py: Python) -> PyResult<Keypair> {
+        self.hotkey_file()?.get_keypair(password, py)
+    }
+
+    /// Creates coldkey from uri string, optionally encrypts it with the user-provided password.
+    #[pyo3(signature = (uri, use_password = true, overwrite = false, suppress = false))]
+    pub fn create_coldkey_from_uri(
+        &mut self,
+        uri: String,
+        use_password: bool,
+        overwrite: bool,
+        suppress: bool,
+        py: Python,
+    ) -> PyResult<Wallet> {
+        let keypair = Keypair::create_from_uri(uri.as_str())?;
+
+        if !suppress {
+            if let Some(m) = keypair.mnemonic()? {
+                display_mnemonic_msg(m.clone(), "coldkey");
+            }
+        }
+
+        self.set_coldkey(keypair.clone(), use_password, overwrite, py)?;
+        self.set_coldkeypub(keypair.clone(), false, overwrite, py)?;
+        Ok(self.clone())
+    }
+
+    /// Creates hotkey from uri string, optionally encrypts it with the user-provided password.
+    #[pyo3(signature = (uri, use_password = true, overwrite = false, suppress = false))]
+    pub fn create_hotkey_from_uri(
+        &mut self,
+        uri: String,
+        use_password: bool,
+        overwrite: bool,
+        suppress: bool,
+        py: Python,
+    ) -> PyResult<Wallet> {
+        let keypair = Keypair::create_from_uri(uri.as_str())?;
+
+        if !suppress {
+            if let Some(m) = keypair.mnemonic()? {
+                display_mnemonic_msg(m.clone(), "hotkey");
+            }
+        }
+
+        self.set_hotkey(keypair.clone(), use_password, overwrite, py)?;
+        Ok(self.clone())
+    }
+
+    /// Unlocks the coldkey.
+    pub fn unlock_coldkey(&mut self, py: Python) -> PyResult<Keypair> {
+        if self._coldkey.is_none() {
+            let coldkey_file = self.coldkey_file()?;
+            self._coldkey = Some(coldkey_file.get_keypair(None, py)?);
+        }
+        let _coldkey = self
+            ._coldkey
+            .clone()
+            .ok_or(PyErr::new::<KeyFileError, _>("Coldkey file doesn't exist."))?;
+        Ok(_coldkey)
+    }
+
+    /// Unlocks the coldkeypub.
+    pub fn unlock_coldkeypub(&mut self, py: Python) -> PyResult<Keypair> {
+        if self._coldkeypub.is_none() {
+            let coldkeypub_file = self.coldkeypub_file()?;
+            self._coldkeypub = Some(coldkeypub_file.get_keypair(None, py)?);
+        }
+        let _coldkeypub = self
+            ._coldkeypub
+            .clone()
+            .ok_or(PyErr::new::<KeyFileError, _>("Coldkey file doesn't exist."))?;
+        Ok(_coldkeypub)
+    }
+
+    /// Unlocks the hotkey.
+    pub fn unlock_hotkey(&mut self, py: Python) -> PyResult<Keypair> {
+        if self._hotkey.is_none() {
+            let hotkey_file = self.hotkey_file()?;
+            self._hotkey = Some(hotkey_file.get_keypair(None, py)?);
+        }
+        let _hotkey = self
+            ._hotkey
+            .clone()
+            .ok_or(PyErr::new::<KeyFileError, _>("Hotkey doesn't exist."))?;
+        Ok(_hotkey)
+    }
+
+    /// Creates a new coldkey, optionally encrypts it with the user-provided password and saves to disk.
+    #[pyo3(signature = (n_words = 12, use_password = true, overwrite = false, suppress = false))]
+    pub fn new_coldkey(
+        &mut self,
+        n_words: usize,
+        use_password: bool,
+        overwrite: bool,
+        suppress: bool,
+        py: Python,
+    ) -> PyResult<Wallet> {
+        self.create_new_coldkey(n_words, use_password, overwrite, suppress, py)
+    }
+
+    /// Creates a new coldkey, optionally encrypts it with the user-provided password and saves to disk.
+    #[pyo3(signature = (n_words=12, use_password=true, overwrite=false, suppress=false))]
+    fn create_new_coldkey(
+        &mut self,
+        n_words: usize,
+        use_password: bool,
+        overwrite: bool,
+        suppress: bool,
+        py: Python,
+    ) -> PyResult<Wallet> {
+        let mnemonic = Keypair::generate_mnemonic(n_words)?;
+        let keypair = Keypair::create_from_mnemonic(&mnemonic)?;
+
+        if !suppress {
+            display_mnemonic_msg(mnemonic, "coldkey");
+        }
+
+        self.set_coldkey(keypair.clone(), use_password, overwrite, py)?;
+        self.set_coldkeypub(keypair.clone(), false, overwrite, py)?;
+
+        Ok(self.clone())
+    }
+
+    /// Creates a new hotkey, optionally encrypts it with the user-provided password and saves to disk.
+    #[pyo3(signature = (n_words = 12, use_password = false, overwrite = false, suppress = false))]
+    pub fn new_hotkey(
+        &mut self,
+        n_words: usize,
+        use_password: bool,
+        overwrite: bool,
+        suppress: bool,
+        py: Python,
+    ) -> PyResult<Wallet> {
+        self.create_new_hotkey(n_words, use_password, overwrite, suppress, py)
+    }
+
+    /// Creates a new hotkey, optionally encrypts it with the user-provided password and saves to disk.
+    #[pyo3(signature = (n_words=12, use_password=false, overwrite=false, suppress=false))]
+    pub fn create_new_hotkey(
+        &mut self,
+        n_words: usize,
+        use_password: bool,
+        overwrite: bool,
+        suppress: bool,
+        py: Python,
+    ) -> PyResult<Wallet> {
+        let mnemonic = Keypair::generate_mnemonic(n_words)?;
+        let keypair = Keypair::create_from_mnemonic(&mnemonic)?;
+
+        if !suppress {
+            display_mnemonic_msg(mnemonic, "hotkey");
+        }
+
+        self.set_hotkey(keypair.clone(), use_password, overwrite, py)?;
+        Ok(self.clone())
+    }
+
+    /// Regenerates the coldkeypub from the passed ``ss58_address`` or public_key and saves the file. Requires either ``ss58_address`` or public_key to be passed.
+    #[pyo3(signature = (ss58_address = None, public_key = None, overwrite = false))]
+    pub fn regenerate_coldkeypub(
+        &mut self,
+        ss58_address: Option<String>,
+        public_key: Option<String>,
+        overwrite: bool,
+        py: Python,
+    ) -> PyResult<Self> {
+        if ss58_address.is_none() && public_key.is_none() {
+            return Err(PyErr::new::<PyValueError, _>(
+                "Either ss58_address or public_key must be passed.",
+            ));
+        }
+
+        // convert from Option<String> to &Bound<PyAny> for `is_valid_bittensor_address_or_public_key`
+        let address_to_string = ss58_address.as_ref().or(public_key.as_ref());
+        let binding_py_string = PyString::new_bound(py, address_to_string.unwrap().as_str());
+        let address_to_check: &Bound<PyAny> = binding_py_string.as_ref();
+
+        if !is_valid_bittensor_address_or_public_key(address_to_check)? {
+            return Err(PyErr::new::<PyValueError, _>(format!(
+                "Invalid {}.",
+                if ss58_address.is_some() {
+                    "ss58_address"
+                } else {
+                    "public_key"
+                }
+            )));
+        }
+
+        let keypair = Keypair::new(ss58_address, public_key, None, 42, None, 1)?;
+
+        self.set_coldkeypub(keypair, overwrite, false, py)?;
+        Ok(self.clone())
+    }
+
+    /// Regenerates the coldkey from the passed mnemonic or seed, or JSON encrypts it with the user's password and saves the file.
+    #[allow(clippy::too_many_arguments)]
+    #[pyo3(signature = (mnemonic=None, seed=None, json=None, use_password=true, overwrite=false, suppress=false))]
+    pub fn regenerate_coldkey(
+        &mut self,
+        mnemonic: Option<String>,
+        seed: Option<String>,
+        json: Option<(String, String)>,
+        use_password: bool,
+        overwrite: bool,
+        suppress: bool,
+        py: Python,
+    ) -> PyResult<Self> {
+        let keypair = if let Some(mnemonic) = mnemonic {
+            // mnemonic
+            let keypair = Keypair::create_from_mnemonic(&mnemonic)?;
+            if !suppress {
+                display_mnemonic_msg(mnemonic, "coldkey");
+            }
+            keypair
+        } else if let Some(seed) = seed {
+            // seed
+            let seed_string: &Bound<PyAny> = &PyString::new_bound(py, seed.as_str());
+            Keypair::create_from_seed(&seed_string.clone())?
+        } else if let Some((json_data, passphrase)) = json {
+            // json_data + passphrase
+            Keypair::create_from_encrypted_json(&json_data, &passphrase)?
+        } else {
+            return Err(PyErr::new::<PyValueError, _>(
+                "Must pass either mnemonic, seed, or json.",
+            ));
+        };
+
+        self.set_coldkey(keypair.clone(), use_password, overwrite, py)?;
+        self.set_coldkeypub(keypair.clone(), false, overwrite, py)?;
+        Ok(self.clone())
+    }
+
+    /// Regenerates the hotkey from passed mnemonic or seed, encrypts it with the user's password and saves the file.
+    #[allow(clippy::too_many_arguments)]
+    #[pyo3(signature = (mnemonic=None, seed=None, json=None, use_password=true, overwrite=false, suppress=false))]
+    pub fn regenerate_hotkey(
+        &mut self,
+        mnemonic: Option<String>,
+        seed: Option<String>,
+        json: Option<(String, String)>,
+        use_password: bool,
+        overwrite: bool,
+        suppress: bool,
+        py: Python,
+    ) -> PyResult<Self> {
+        let keypair = if let Some(mnemonic) = mnemonic {
+            // mnemonic
+            let keypair = Keypair::create_from_mnemonic(&mnemonic)?;
+            if !suppress {
+                display_mnemonic_msg(mnemonic, "hotkey");
+            }
+            keypair
+        } else if let Some(seed) = seed {
+            // seed
+            let seed_string: &Bound<PyAny> = &PyString::new_bound(py, seed.as_str());
+            Keypair::create_from_seed(&seed_string.clone())?
+        } else if let Some((json_data, passphrase)) = json {
+            // json_data + passphrase
+            Keypair::create_from_encrypted_json(&json_data, &passphrase)?
+        } else {
+            return Err(PyErr::new::<PyValueError, _>(
+                "Must pass either mnemonic, seed, or json.",
+            ));
+        };
+
+        self.set_hotkey(keypair, use_password, overwrite, py)?;
+
+        Ok(self.clone())
+    }
+}


Test patch:
diff --git a/tests/test_keyfile.py b/tests/test_keyfile.py
index 7c01027..b8c33aa 100644
--- a/tests/test_keyfile.py
+++ b/tests/test_keyfile.py
@@ -20,16 +20,13 @@
 import time
 import pytest
 import shutil
-import unittest.mock as mock
-from scalecodec import ScaleBytes
-from substrateinterface import Keypair, KeypairType
-from substrateinterface.constants import DEV_PHRASE
-from substrateinterface.exceptions import ConfigurationError
+
 from bip39 import bip39_validate
 
 from bittensor_wallet.keyfile import get_coldkey_password_from_environment
 from bittensor_wallet.keyfile import Keyfile
-from bittensor_wallet.errors import KeyFileError
+from bittensor_wallet.errors import ConfigurationError
+from bittensor_wallet.keypair import Keypair
 
 
 def test_generate_mnemonic():
@@ -53,8 +50,8 @@ def test_create_sr25519_keypair():
     Test the creation of a sr25519 keypair from a mnemonic and verify the SS58 address.
     """
     mnemonic = "old leopard transfer rib spatial phone calm indicate online fire caution review"
-    keypair = Keypair.create_from_mnemonic(mnemonic, ss58_format=0)
-    assert keypair.ss58_address == "16ADqpMa4yzfmWs3nuTSMhfZ2ckeGtvqhPWCNqECEGDcGgU2"
+    keypair = Keypair.create_from_mnemonic(mnemonic)
+    assert keypair.ss58_address == "5HDvhV6WDCjCKyrXqGQSDYqQAzkzabNhctmiDYEqgBC66BsX"
 
 
 def test_only_provide_ss58_address():
@@ -75,10 +72,10 @@ def test_only_provide_public_key():
     """
     keypair = Keypair(
         public_key="0xe4359ad3e2716c539a1d663ebd0a51bdc5c98a12e663bb4c4402db47828c9446",
-        ss58_format=0,
+        ss58_format=42,
     )
 
-    assert keypair.ss58_address == "16ADqpMa4yzfmWs3nuTSMhfZ2ckeGtvqhPWCNqECEGDcGgU2"
+    assert keypair.ss58_address == "5HDvhV6WDCjCKyrXqGQSDYqQAzkzabNhctmiDYEqgBC66BsX"
 
 
 def test_provide_no_ss58_address_and_public_key():
@@ -128,15 +125,16 @@ def test_sign_and_verify_hex_data():
     assert keypair.verify("0x1234", signature) is True
 
 
-def test_sign_and_verify_scale_bytes():
-    """
-    Test the signing and verification of ScaleBytes data using a keypair.
-    """
-    mnemonic = Keypair.generate_mnemonic()
-    keypair = Keypair.create_from_mnemonic(mnemonic)
-    data = ScaleBytes("0x1234")
-    signature = keypair.sign(data)
-    assert keypair.verify(data, signature) is True
+# TODO: need to implement this ScaleBytes processing as option (src/keypair.rs:368)
+# def test_sign_and_verify_scale_bytes():
+#     """
+#     Test the signing and verification of ScaleBytes data using a keypair.
+#     """
+#     mnemonic = Keypair.generate_mnemonic()
+#     keypair = Keypair.create_from_mnemonic(mnemonic)
+#     data = ScaleBytes("0x1234")
+#     signature = keypair.sign(data)
+#     assert keypair.verify(data, signature) is True
 
 
 def test_sign_missing_private_key():
@@ -148,32 +146,6 @@ def test_sign_missing_private_key():
         keypair.sign("0x1234")
 
 
-def test_sign_unsupported_crypto_type():
-    """
-    Test signing a message with an unsupported crypto type.
-    """
-    keypair = Keypair.create_from_private_key(
-        ss58_address="16ADqpMa4yzfmWs3nuTSMhfZ2ckeGtvqhPWCNqECEGDcGgU2",
-        private_key="0x1f1995bdf3a17b60626a26cfe6f564b337d46056b7a1281b64c649d592ccda0a9cffd34d9fb01cae1fba61aeed184c817442a2186d5172416729a4b54dd4b84e",
-        crypto_type=3,
-    )
-    with pytest.raises(ConfigurationError):
-        keypair.sign("0x1234")
-
-
-def test_verify_unsupported_crypto_type():
-    """
-    Test verifying a signature with an unsupported crypto type.
-    """
-    keypair = Keypair.create_from_private_key(
-        ss58_address="16ADqpMa4yzfmWs3nuTSMhfZ2ckeGtvqhPWCNqECEGDcGgU2",
-        private_key="0x1f1995bdf3a17b60626a26cfe6f564b337d46056b7a1281b64c649d592ccda0a9cffd34d9fb01cae1fba61aeed184c817442a2186d5172416729a4b54dd4b84e",
-        crypto_type=3,
-    )
-    with pytest.raises(ConfigurationError):
-        keypair.verify("0x1234", "0x1234")
-
-
 def test_sign_and_verify_incorrect_signature():
     """
     Test verifying an incorrect signature for a signed message.
@@ -191,7 +163,7 @@ def test_sign_and_verify_invalid_signature():
     mnemonic = Keypair.generate_mnemonic()
     keypair = Keypair.create_from_mnemonic(mnemonic)
     signature = "Test"
-    with pytest.raises(TypeError):
+    with pytest.raises(ValueError):
         keypair.verify("Test1231223123123", signature)
 
 
@@ -205,42 +177,11 @@ def test_sign_and_verify_invalid_message():
     assert keypair.verify("OtherMessage", signature) is False
 
 
-def test_create_ed25519_keypair():
-    """
-    Test the creation of an ed25519 keypair from a mnemonic and verify the SS58 address.
-    """
-    mnemonic = "old leopard transfer rib spatial phone calm indicate online fire caution review"
-    keypair = Keypair.create_from_mnemonic(
-        mnemonic, ss58_format=0, crypto_type=KeypairType.ED25519
-    )
-    assert keypair.ss58_address == "16dYRUXznyhvWHS1ktUENGfNAEjCawyDzHRtN9AdFnJRc38h"
-
-
-def test_sign_and_verify_ed25519():
-    """
-    Test the signing and verification of a message using an ed25519 keypair.
-    """
-    mnemonic = Keypair.generate_mnemonic()
-    keypair = Keypair.create_from_mnemonic(mnemonic, crypto_type=KeypairType.ED25519)
-    signature = keypair.sign("Test1231223123123")
-    assert keypair.verify("Test1231223123123", signature) is True
-
-
-def test_sign_and_verify_invalid_signature_ed25519():
-    """
-    Test verifying an incorrect signature for a message signed with an ed25519 keypair.
-    """
-    mnemonic = Keypair.generate_mnemonic()
-    keypair = Keypair.create_from_mnemonic(mnemonic, crypto_type=KeypairType.ED25519)
-    signature = "0x4c291bfb0bb9c1274e86d4b666d13b2ac99a0bacc04a4846fb8ea50bda114677f83c1f164af58fc184451e5140cc8160c4de626163b11451d3bbb208a1889f8a"
-    assert keypair.verify("Test1231223123123", signature) is False
-
-
 def test_unsupport_crypto_type():
     """
     Test creating a keypair with an unsupported crypto type.
     """
-    with pytest.raises(ValueError):
+    with pytest.raises(TypeError):
         Keypair.create_from_seed(
             seed_hex="0xda3cf5b1e9144931?a0f0db65664aab662673b099415a7f8121b7245fb0be4143",
             crypto_type=2,
@@ -252,7 +193,6 @@ def test_create_keypair_from_private_key():
     Test creating a keypair from a private key and verify the public key.
     """
     keypair = Keypair.create_from_private_key(
-        ss58_address="16ADqpMa4yzfmWs3nuTSMhfZ2ckeGtvqhPWCNqECEGDcGgU2",
         private_key="0x1f1995bdf3a17b60626a26cfe6f564b337d46056b7a1281b64c649d592ccda0a9cffd34d9fb01cae1fba61aeed184c817442a2186d5172416729a4b54dd4b84e",
     )
     assert (
@@ -322,12 +262,6 @@ def test_hdkd_path_gt_32_bytes():
     assert derivation_address == derived_keypair.ss58_address
 
 
-def test_hdkd_unsupported_password():
-    """Test hierarchical deterministic key derivation with an unsupported password."""
-    with pytest.raises(NotImplementedError):
-        Keypair.create_from_uri(f"{DEV_PHRASE}///test")
-
-
 def create_keyfile(root_path):
     """
     Creates a keyfile object with two keypairs: alice and bob.
@@ -418,42 +352,6 @@ def test_create(keyfile_setup_teardown):
     repr(keyfile)
 
 
-def test_legacy_coldkey(keyfile_setup_teardown):
-    """
-    Test case for legacy cold keyfile.
-    """
-    root_path = keyfile_setup_teardown
-    legacy_filename = os.path.join(root_path, "coldlegacy_keyfile")
-    keyfile = Keyfile(path=legacy_filename)
-    keyfile.make_dirs()
-    keyfile_data = b"0x32939b6abc4d81f02dff04d2b8d1d01cc8e71c5e4c7492e4fa6a238cdca3512f"
-    with open(legacy_filename, "wb") as keyfile_obj:
-        keyfile_obj.write(keyfile_data)
-    assert keyfile.keyfile_data == keyfile_data
-    keyfile.encrypt(password="this is the fake password")
-    keyfile.decrypt(password="this is the fake password")
-    expected_decryption = {
-        "accountId": "0x32939b6abc4d81f02dff04d2b8d1d01cc8e71c5e4c7492e4fa6a238cdca3512f",
-        "publicKey": "0x32939b6abc4d81f02dff04d2b8d1d01cc8e71c5e4c7492e4fa6a238cdca3512f",
-        "privateKey": None,
-        "secretPhrase": None,
-        "secretSeed": None,
-        "ss58Address": "5DD26kC2kxajmwfbbZmVmxhrY9VeeyR1Gpzy9i8wxLUg6zxm",
-    }
-    for key, value in expected_decryption.items():
-        value_str = f'"{value}"' if value is not None else "null"
-        assert f'"{key}": {value_str}'.encode() in keyfile.keyfile_data
-
-    assert (
-        keyfile.get_keypair().ss58_address
-        == "5DD26kC2kxajmwfbbZmVmxhrY9VeeyR1Gpzy9i8wxLUg6zxm"
-    )
-    assert (
-        f"0x{keyfile.get_keypair().public_key.hex()}"
-        == "0x32939b6abc4d81f02dff04d2b8d1d01cc8e71c5e4c7492e4fa6a238cdca3512f"
-    )
-
-
 def test_validate_password():
     """
     Test case for the validate_password function.
@@ -463,92 +361,46 @@ def test_validate_password():
     """
     from bittensor_wallet.keyfile import validate_password
 
-    assert validate_password(None) is False
+    with pytest.raises(TypeError):
+        validate_password(None)
     assert validate_password("passw0rd") is False
     assert validate_password("123456789") is False
-    with mock.patch("getpass.getpass", return_value="biTTensor"):
-        assert validate_password("biTTensor") is True
-    with mock.patch("getpass.getpass", return_value="biTTenso"):
-        assert validate_password("biTTensor") is False
-
-
-def test_decrypt_keyfile_data_legacy():
-    """
-    Test case for decrypting legacy keyfile data.
-
-    This test case verifies that the `decrypt_keyfile_data` function correctly decrypts
-    encrypted data using a legacy encryption scheme.
-
-    The test generates a key using a password and encrypts a sample data. Then, it decrypts
-    the encrypted data using the same password and asserts that the decrypted data matches
-    the original data.
-    """
-    import base64
-
-    from cryptography.fernet import Fernet
-    from cryptography.hazmat.backends import default_backend
-    from cryptography.hazmat.primitives import hashes
-    from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
-
-    from bittensor_wallet.keyfile import decrypt_keyfile_data
 
-    __SALT = b"Iguesscyborgslikemyselfhaveatendencytobeparanoidaboutourorigins"
 
-    def __generate_key(password):
-        kdf = PBKDF2HMAC(
-            algorithm=hashes.SHA256(),
-            salt=__SALT,
-            length=32,
-            iterations=10000000,
-            backend=default_backend(),
-        )
-        key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
-        return key
-
-    pw = "fakepasssword238947239"
-    data = b"encrypt me!"
-    key = __generate_key(pw)
-    cipher_suite = Fernet(key)
-    encrypted_data = cipher_suite.encrypt(data)
-
-    decrypted_data = decrypt_keyfile_data(encrypted_data, pw)
-    assert decrypted_data == data
-
-
-def test_user_interface():
-    """
-    Test the user interface for asking password to encrypt.
-
-    This test case uses the `ask_password_to_encrypt` function from the `bittensor.keyfile` module.
-    It mocks the `getpass.getpass` function to simulate user input of passwords.
-    The expected result is that the `ask_password_to_encrypt` function returns the correct password.
-    """
-    from bittensor_wallet.keyfile import ask_password_to_encrypt
-
-    with mock.patch(
-        "getpass.getpass",
-        side_effect=["pass", "password", "asdury3294y", "asdury3294y"],
-    ):
-        assert ask_password_to_encrypt() == "asdury3294y"
-
-
-def test_overwriting(keyfile_setup_teardown):
-    """
-    Test case for overwriting a keypair in the keyfile.
-    """
-    root_path = keyfile_setup_teardown
-    keyfile = Keyfile(path=os.path.join(root_path, "keyfile"))
-    alice = Keypair.create_from_uri("/Alice")
-    keyfile.set_keypair(
-        alice, encrypt=True, overwrite=True, password="thisisafakepassword"
-    )
-    bob = Keypair.create_from_uri("/Bob")
-
-    with pytest.raises(KeyFileError):
-        with mock.patch("builtins.input", return_value="n"):
-            keyfile.set_keypair(
-                bob, encrypt=True, overwrite=False, password="thisisafakepassword"
-            )
+# def test_user_interface():
+#     """
+#     Test the user interface for asking password to encrypt.
+#
+#     This test case uses the `ask_password_to_encrypt` function from the `bittensor.keyfile` module.
+#     It mocks the `getpass.getpass` function to simulate user input of passwords.
+#     The expected result is that the `ask_password_to_encrypt` function returns the correct password.
+#     """
+#     from bittensor_wallet.keyfile import ask_password_to_encrypt
+#
+#     with mock.patch(
+#         "getpass.getpass",
+#         side_effect=["pass", "password", "asdury3294y", "asdury3294y"],
+#     ):
+#         assert ask_password_to_encrypt() == "asdury3294y"
+
+
+# def test_overwriting(keyfile_setup_teardown):
+#     """
+#     Test case for overwriting a keypair in the keyfile.
+#     """
+#     root_path = keyfile_setup_teardown
+#     keyfile = Keyfile(path=os.path.join(root_path, "keyfile"))
+#     alice = Keypair.create_from_uri("/Alice")
+#     keyfile.set_keypair(
+#         alice, encrypt=True, overwrite=True, password="thisisafakepassword"
+#     )
+#     bob = Keypair.create_from_uri("/Bob")
+#
+#     with pytest.raises(KeyFileError):
+#         with mock.patch("builtins.input", return_value="n"):
+#             keyfile.set_keypair(
+#                 bob, encrypt=True, overwrite=False, password="thisisafakepassword"
+#             )
 
 
 def test_serialized_keypair_to_keyfile_data(keyfile_setup_teardown):
@@ -615,8 +467,8 @@ def test_get_coldkey_password_from_environment(monkeypatch):
         "my-wallet": "password2",
     }
 
-    monkeypatch.setenv("bt_cold_pw_wallet", password_by_wallet["WALLET"])
-    monkeypatch.setenv("BT_COLD_PW_My_Wallet", password_by_wallet["my_wallet"])
+    monkeypatch.setenv("bt_cold_pw_wallet".upper(), password_by_wallet["WALLET"])
+    monkeypatch.setenv("BT_COLD_PW_My_Wallet".upper(), password_by_wallet["my_wallet"])
 
     for wallet, password in password_by_wallet.items():
         assert get_coldkey_password_from_environment(wallet) == password
diff --git a/tests/test_utils.py b/tests/test_utils.py
index a40101b..9731f06 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -21,65 +21,50 @@
 
 def test_get_ss58_format(mocker):
     """Checks that `get_ss58_format` function uses `ss58.get_ss58_format` call."""
-
     # Preps
-
-    spy_get_ss58_format = mocker.spy(utils.ss58, "get_ss58_format")
     fake_ss58_addressss58_address = "5FvUhL6sQ5egLAvnyiY1n7gTuhmYg9sD3oJbvASWkpNULt3n"
 
-    # Call
-    result = utils.get_ss58_format(fake_ss58_addressss58_address)
-
-    # Asserts
-    spy_get_ss58_format.assert_called_once_with(fake_ss58_addressss58_address)
-    assert result == 42
+    # Assertions
+    assert utils.get_ss58_format(fake_ss58_addressss58_address) == 42
 
 
 @pytest.mark.parametrize(
-    "address, valid_ss58_return_values, expected_result",
+    "address, expected_result",
     [
         # Valid ss58 address for SS58_FORMAT
-        ("5F3sa2TJAWMqDhXG6jhV4N8ko9rLbc4B52kmxXJoN5D3ue8w", [True, False], True),
+        ("5F3sa2TJAWMqDhXG6jhV4N8ko9rLbc4B52kmxXJoN5D3ue8w", False),
         # Valid ss58 address for default substrate format
-        ("5DAAnrj7VHTz5J6N4kP9TB8XJYkJptJSwj7UEZBrVXkNk59e", [False, True], True),
+        ("5HQV5mjTgcM9aEBi4xbnbiJdz8aez92tWyRc1U53rLYuYEMk", True),
         # Invalid ss58 address
-        ("InvalidAddress", [False, False], False),
+        ("InvalidAddress", False),
     ],
 )
-def test_is_valid_ss58_address(
-    mocker, address, valid_ss58_return_values, expected_result
-):
+def test_is_valid_ss58_address(address, expected_result):
     """Test `is_valid_ss58_address` function with different inputs."""
 
     # Mock ss58.is_valid_ss58_address
-    mock_ss58_is_valid = mocker.patch(
-        "substrateinterface.utils.ss58.is_valid_ss58_address"
-    )
-    mock_ss58_is_valid.side_effect = valid_ss58_return_values
-
     assert utils.is_valid_ss58_address(address) == expected_result
-    mock_ss58_is_valid.assert_any_call(address, valid_ss58_format=42)
 
 
-@pytest.mark.parametrize(
-    "address, side_effect, expected_result",
-    [
-        ("InvalidAddress", IndexError, False),  # IndexError should return False
-    ],
-)
-def test_is_valid_ss58_address_with_exceptions(
-    mocker, address, side_effect, expected_result
-):
-    """Tests `is_valid_ss58_address` function with exceptions."""
-
-    # Mock ss58.is_valid_ss58_address to raise an exception
-    mock_ss58_is_valid = mocker.patch(
-        "substrateinterface.utils.ss58.is_valid_ss58_address"
-    )
-    mock_ss58_is_valid.side_effect = side_effect
-
-    assert utils.is_valid_ss58_address(address) == expected_result
-    mock_ss58_is_valid.assert_any_call(address, valid_ss58_format=42)
+# @pytest.mark.parametrize(
+#     "address, side_effect, expected_result",
+#     [
+#         ("InvalidAddress", IndexError, False),  # IndexError should return False
+#     ],
+# )
+# def test_is_valid_ss58_address_with_exceptions(
+#     mocker, address, side_effect, expected_result
+# ):
+#     """Tests `is_valid_ss58_address` function with exceptions."""
+#
+#     # Mock ss58.is_valid_ss58_address to raise an exception
+#     mock_ss58_is_valid = mocker.patch(
+#         "substrateinterface.utils.ss58.is_valid_ss58_address"
+#     )
+#     mock_ss58_is_valid.side_effect = side_effect
+#
+#     assert utils.is_valid_ss58_address(address) == expected_result
+#     mock_ss58_is_valid.assert_any_call(address, valid_ss58_format=42)
 
 
 @pytest.mark.parametrize(
@@ -90,28 +75,28 @@ def test_is_valid_ss58_address_with_exceptions(
         # Valid 66-character string public key (with 0x prefix)
         ("a" * 66, False),
         # Valid 32-byte public key
-        (b"a" * 32, True),
+        (b"a" * 32, False),
         # Invalid: 63-character string public key
         ("a" * 63, False),
     ],
 )
-def test_is_valid_ed25519_pubkey(mocker, public_key, is_valid):
+def test_is_valid_ed25519_pubkey(public_key, is_valid):
     """Test is_valid_ed25519_pubkey function with different inputs."""
     assert utils.is_valid_ed25519_pubkey(public_key) == is_valid
 
 
 @pytest.mark.parametrize(
-    "address",
+    "address, excepted_result",
     [
         # Valid ss58 address `a` * 64
-        "5FvUhL6sQ5egLAvnyiY1n7gTuhmYg9sD3oJbvASWkpNULt3n",
+        ("5FvUhL6sQ5egLAvnyiY1n7gTuhmYg9sD3oJbvASWkpNULt3n", True),
         # Valid 64-character ed25519 public key
-        "0x" + "a" * 64,
+        ("0x" + "a" * 64, True),
         # Valid 32-byte ed25519 public key
-        b"a" * 32,
+        (b"a" * 32, False),
     ],
 )
-def test_is_valid_bittensor_address_or_public_key_integration(address):
+def test_is_valid_bittensor_address_or_public_key_integration(address, excepted_result):
     """Integration test for is_valid_bittensor_address_or_public_key function."""
 
-    assert utils.is_valid_bittensor_address_or_public_key(address) is True
+    assert utils.is_valid_bittensor_address_or_public_key(address) is excepted_result
diff --git a/tests/test_wallet.py b/tests/test_wallet.py
index 3dd0fd8..02acadb 100644
--- a/tests/test_wallet.py
+++ b/tests/test_wallet.py
@@ -18,11 +18,7 @@
 import json
 import time
 import pytest
-import random
-import re
 from bittensor_wallet import Wallet, keyfile
-from bittensor_wallet.errors import KeyFileError
-from rich.prompt import Confirm
 from ansible_vault import Vault
 from unittest.mock import patch
 
@@ -133,131 +129,132 @@ def test_encrypt_and_decrypt():
     assert keyfile.keyfile_data_is_encrypted_ansible(encrypted_message)
 
 
-def test_check_and_update_encryption_not_updated(wallet_update_setup):
-    """Test for a few cases where wallet should not be updated.
-    1. When the wallet is already updated.
-    2. When it is the hotkey.
-    3. When the wallet is empty.
-    4. When the wallet is legacy but no prompt to ask for password.
-    5. When the password is wrong.
-    """
-    wallet = wallet_update_setup["wallet"]
-    empty_wallet = wallet_update_setup["empty_wallet"]
-    legacy_wallet = wallet_update_setup["legacy_wallet"]
-    default_legacy_password = wallet_update_setup["default_legacy_password"]
-    # test the checking with no rewriting needs to be done.
-    with patch.object(keyfile, "encrypt_keyfile_data") as encrypt:
-        # self.wallet is already the most updated with nacl encryption.
-        assert wallet.coldkey_file.check_and_update_encryption()
-
-        # hotkey_file is not encrypted, thus do not need to be updated.
-        assert not wallet.hotkey_file.check_and_update_encryption()
-
-        # empty_wallet has not been created, thus do not need to be updated.
-        assert not empty_wallet.coldkey_file.check_and_update_encryption()
-
-        # legacy wallet cannot be updated without asking for password form prompt.
-        assert not legacy_wallet.coldkey_file.check_and_update_encryption(
-            no_prompt=True
-        )
-
-        # Wrong password
-        legacy_wallet = create_legacy_wallet(
-            default_legacy_password=default_legacy_password
-        )
-        with patch("getpass.getpass", return_value="wrong_password"), patch.object(
-            Confirm, "ask", return_value=False
-        ):
-            assert not legacy_wallet.coldkey_file.check_and_update_encryption()
-
-        # no renewal has been done in this test.
-        assert not encrypt.called
-
-
-def test_check_and_update_excryption(wallet_update_setup, legacy_wallet=None):
-    """Test for the alignment of the updated VS old wallet.
-    1. Same coldkey_file data.
-    2. Same coldkey path.
-    3. Same hotkey_file data.
-    4. Same hotkey path.
-    5. same password.
-
-    Read the updated wallet in 2 ways.
-    1. Directly as the output of check_and_update_encryption()
-    2. Read from file using the same coldkey and hotkey name
-    """
-    default_legacy_password = wallet_update_setup["default_legacy_password"]
-
-    def check_new_coldkey_file(keyfile_):
-        new_keyfile_data = keyfile_._read_keyfile_data_from_file()
-        new_decrypted_keyfile_data = keyfile.decrypt_keyfile_data(
-            new_keyfile_data, legacy_password
-        )
-        new_path = legacy_wallet.coldkey_file.path
-
-        assert old_coldkey_file_data is not None
-        assert new_keyfile_data is not None
-        assert not old_coldkey_file_data == new_keyfile_data
-        assert keyfile.keyfile_data_is_encrypted_ansible(old_coldkey_file_data)
-        assert keyfile.keyfile_data_is_encrypted_nacl(new_keyfile_data)
-        assert not keyfile.keyfile_data_is_encrypted_nacl(old_coldkey_file_data)
-        assert not keyfile.keyfile_data_is_encrypted_ansible(new_keyfile_data)
-        assert old_decrypted_coldkey_file_data == new_decrypted_keyfile_data
-        assert new_path == old_coldkey_path
-
-    def check_new_hotkey_file(keyfile_):
-        new_keyfile_data = keyfile_._read_keyfile_data_from_file()
-        new_path = legacy_wallet.hotkey_file.path
-
-        assert old_hotkey_file_data == new_keyfile_data
-        assert new_path == old_hotkey_path
-        assert not keyfile.keyfile_data_is_encrypted(new_keyfile_data)
-
-    if legacy_wallet is None:
-        legacy_password = f"PASSword-{random.randint(0, 10000)}"
-        legacy_wallet = create_legacy_wallet(legacy_password=legacy_password)
-
-    else:
-        legacy_password = default_legacy_password
-
-    # get old cold keyfile data
-    old_coldkey_file_data = legacy_wallet.coldkey_file._read_keyfile_data_from_file()
-    old_decrypted_coldkey_file_data = keyfile.decrypt_keyfile_data(
-        old_coldkey_file_data, legacy_password
-    )
-    old_coldkey_path = legacy_wallet.coldkey_file.path
-
-    # get old hot keyfile data
-    old_hotkey_file_data = legacy_wallet.hotkey_file._read_keyfile_data_from_file()
-    old_hotkey_path = legacy_wallet.hotkey_file.path
-
-    # update legacy_wallet from ansible to nacl
-    with patch("getpass.getpass", return_value=legacy_password), patch.object(
-        Confirm, "ask", return_value=True
-    ):
-        legacy_wallet.coldkey_file.check_and_update_encryption()
-
-    # get new keyfile data from the same legacy wallet
-    check_new_coldkey_file(legacy_wallet.coldkey_file)
-    check_new_hotkey_file(legacy_wallet.hotkey_file)
-
-    # get new keyfile data from wallet name
-    updated_legacy_wallet = Wallet(
-        name=legacy_wallet.name,
-        hotkey=legacy_wallet.hotkey_str,
-        path="/tmp/tests_wallets/do_not_use",
-    )
-    check_new_coldkey_file(updated_legacy_wallet.coldkey_file)
-    check_new_hotkey_file(updated_legacy_wallet.hotkey_file)
-
-    # def test_password_retain(self):
-    # [tick] test the same password works
-    # [tick] try to read using the same hotkey/coldkey name
-    # [tick] test the same keyfile data could be retained
-    # [tick] test what if a wrong password was inserted
-    # [no need] try to read from the new file path
-    # [tick] test the old and new encrypted is not the same
-    # [tick] test that the hotkeys are not affected
+#
+# def test_check_and_update_encryption_not_updated(wallet_update_setup):
+#     """Test for a few cases where wallet should not be updated.
+#     1. When the wallet is already updated.
+#     2. When it is the hotkey.
+#     3. When the wallet is empty.
+#     4. When the wallet is legacy but no prompt to ask for password.
+#     5. When the password is wrong.
+#     """
+#     wallet = wallet_update_setup["wallet"]
+#     empty_wallet = wallet_update_setup["empty_wallet"]
+#     legacy_wallet = wallet_update_setup["legacy_wallet"]
+#     default_legacy_password = wallet_update_setup["default_legacy_password"]
+#     # test the checking with no rewriting needs to be done.
+#     with patch.object(keyfile, "encrypt_keyfile_data") as encrypt:
+#         # self.wallet is already the most updated with nacl encryption.
+#         assert wallet.coldkey_file.check_and_update_encryption()
+#
+#         # hotkey_file is not encrypted, thus do not need to be updated.
+#         assert not wallet.hotkey_file.check_and_update_encryption()
+#
+#         # empty_wallet has not been created, thus do not need to be updated.
+#         assert not empty_wallet.coldkey_file.check_and_update_encryption()
+#
+#         # legacy wallet cannot be updated without asking for password form prompt.
+#         assert not legacy_wallet.coldkey_file.check_and_update_encryption(
+#             no_prompt=True
+#         )
+#
+#         # Wrong password
+#         legacy_wallet = create_legacy_wallet(
+#             default_legacy_password=default_legacy_password
+#         )
+#         with patch("getpass.getpass", return_value="wrong_password"), patch.object(
+#             Confirm, "ask", return_value=False
+#         ):
+#             assert not legacy_wallet.coldkey_file.check_and_update_encryption()
+#
+#         # no renewal has been done in this test.
+#         assert not encrypt.called
+#
+#
+# def test_check_and_update_excryption(wallet_update_setup, legacy_wallet=None):
+#     """Test for the alignment of the updated VS old wallet.
+#     1. Same coldkey_file data.
+#     2. Same coldkey path.
+#     3. Same hotkey_file data.
+#     4. Same hotkey path.
+#     5. same password.
+#
+#     Read the updated wallet in 2 ways.
+#     1. Directly as the output of check_and_update_encryption()
+#     2. Read from file using the same coldkey and hotkey name
+#     """
+#     default_legacy_password = wallet_update_setup["default_legacy_password"]
+#
+#     def check_new_coldkey_file(keyfile_):
+#         new_keyfile_data = keyfile_._read_keyfile_data_from_file()
+#         new_decrypted_keyfile_data = keyfile.decrypt_keyfile_data(
+#             new_keyfile_data, legacy_password
+#         )
+#         new_path = legacy_wallet.coldkey_file.path
+#
+#         assert old_coldkey_file_data is not None
+#         assert new_keyfile_data is not None
+#         assert not old_coldkey_file_data == new_keyfile_data
+#         assert keyfile.keyfile_data_is_encrypted_ansible(old_coldkey_file_data)
+#         assert keyfile.keyfile_data_is_encrypted_nacl(new_keyfile_data)
+#         assert not keyfile.keyfile_data_is_encrypted_nacl(old_coldkey_file_data)
+#         assert not keyfile.keyfile_data_is_encrypted_ansible(new_keyfile_data)
+#         assert old_decrypted_coldkey_file_data == new_decrypted_keyfile_data
+#         assert new_path == old_coldkey_path
+#
+#     def check_new_hotkey_file(keyfile_):
+#         new_keyfile_data = keyfile_._read_keyfile_data_from_file()
+#         new_path = legacy_wallet.hotkey_file.path
+#
+#         assert old_hotkey_file_data == new_keyfile_data
+#         assert new_path == old_hotkey_path
+#         assert not keyfile.keyfile_data_is_encrypted(new_keyfile_data)
+#
+#     if legacy_wallet is None:
+#         legacy_password = f"PASSword-{random.randint(0, 10000)}"
+#         legacy_wallet = create_legacy_wallet(legacy_password=legacy_password)
+#
+#     else:
+#         legacy_password = default_legacy_password
+#
+#     # get old cold keyfile data
+#     old_coldkey_file_data = legacy_wallet.coldkey_file._read_keyfile_data_from_file()
+#     old_decrypted_coldkey_file_data = keyfile.decrypt_keyfile_data(
+#         old_coldkey_file_data, legacy_password
+#     )
+#     old_coldkey_path = legacy_wallet.coldkey_file.path
+#
+#     # get old hot keyfile data
+#     old_hotkey_file_data = legacy_wallet.hotkey_file._read_keyfile_data_from_file()
+#     old_hotkey_path = legacy_wallet.hotkey_file.path
+#
+#     # update legacy_wallet from ansible to nacl
+#     with patch("getpass.getpass", return_value=legacy_password), patch.object(
+#         Confirm, "ask", return_value=True
+#     ):
+#         legacy_wallet.coldkey_file.check_and_update_encryption()
+#
+#     # get new keyfile data from the same legacy wallet
+#     check_new_coldkey_file(legacy_wallet.coldkey_file)
+#     check_new_hotkey_file(legacy_wallet.hotkey_file)
+#
+#     # get new keyfile data from wallet name
+#     updated_legacy_wallet = Wallet(
+#         name=legacy_wallet.name,
+#         hotkey=legacy_wallet.hotkey_str,
+#         path="/tmp/tests_wallets/do_not_use",
+#     )
+#     check_new_coldkey_file(updated_legacy_wallet.coldkey_file)
+#     check_new_hotkey_file(updated_legacy_wallet.hotkey_file)
+#
+#     # def test_password_retain(self):
+#     # [tick] test the same password works
+#     # [tick] try to read using the same hotkey/coldkey name
+#     # [tick] test the same keyfile data could be retained
+#     # [tick] test what if a wrong password was inserted
+#     # [no need] try to read from the new file path
+#     # [tick] test the old and new encrypted is not the same
+#     # [tick] test that the hotkeys are not affected
 
 
 @pytest.fixture
@@ -273,58 +270,59 @@ def mock_wallet():
     return wallet
 
 
-def test_regen_coldkeypub_from_ss58_addr(mock_wallet):
-    """Test the `regenerate_coldkeypub` method of the wallet class, which regenerates the cold key pair from an SS58 address.
-    It checks whether the `set_coldkeypub` method is called with the expected arguments, and verifies that the generated key pair's SS58 address matches the input SS58 address.
-    It also tests the behavior when an invalid SS58 address is provided, raising a `ValueError` as expected.
-    """
-    ss58_address = "5DD26kC2kxajmwfbbZmVmxhrY9VeeyR1Gpzy9i8wxLUg6zxm"
-    with patch.object(mock_wallet, "set_coldkeypub") as mock_set_coldkeypub:
-        mock_wallet.regenerate_coldkeypub(ss58_address=ss58_address, overwrite=True)
-
-        mock_set_coldkeypub.assert_called_once()
-        keypair: keyfile.Keypair = mock_set_coldkeypub.call_args_list[0][0][0]
-        assert keypair.ss58_address == ss58_address
-
-    ss58_address_bad = (
-        "5DD26kC2kxajmwfbbZmVmxhrY9VeeyR1Gpzy9i8wxLUg6zx"  # 1 character short
-    )
-    with pytest.raises(ValueError):
-        mock_wallet.regenerate_coldkeypub(ss58_address=ss58_address_bad, overwrite=True)
-
-
-def test_regen_coldkeypub_from_hex_pubkey_str(mock_wallet):
-    """Test the `regenerate_coldkeypub` method of the wallet class, which regenerates the cold key pair from a hex public key string.
-    It checks whether the `set_coldkeypub` method is called with the expected arguments, and verifies that the generated key pair's public key matches the input public key.
-    It also tests the behavior when an invalid public key string is provided, raising a `ValueError` as expected.
-    """
-    pubkey_str = "0x32939b6abc4d81f02dff04d2b8d1d01cc8e71c5e4c7492e4fa6a238cdca3512f"
-    with patch.object(mock_wallet, "set_coldkeypub") as mock_set_coldkeypub:
-        mock_wallet.regenerate_coldkeypub(public_key=pubkey_str, overwrite=True)
-
-        mock_set_coldkeypub.assert_called_once()
-        keypair: keyfile.Keypair = mock_set_coldkeypub.call_args_list[0][0][0]
-        assert "0x" + keypair.public_key.hex() == pubkey_str
-
-    pubkey_str_bad = "0x32939b6abc4d81f02dff04d2b8d1d01cc8e71c5e4c7492e4fa6a238cdca3512"  # 1 character short
-    with pytest.raises(ValueError):
-        mock_wallet.regenerate_coldkeypub(ss58_address=pubkey_str_bad, overwrite=True)
-
-
-def test_regen_coldkeypub_from_hex_pubkey_bytes(mock_wallet):
-    """Test the `regenerate_coldkeypub` method of the wallet class, which regenerates the cold key pair from a hex public key byte string.
-    It checks whether the `set_coldkeypub` method is called with the expected arguments, and verifies that the generated key pair's public key matches the input public key.
-    """
-    pubkey_str = "0x32939b6abc4d81f02dff04d2b8d1d01cc8e71c5e4c7492e4fa6a238cdca3512f"
-    pubkey_bytes = bytes.fromhex(pubkey_str[2:])  # Remove 0x from beginning
-    with patch.object(mock_wallet, "set_coldkeypub") as mock_set_coldkeypub:
-        mock_wallet.regenerate_coldkeypub(public_key=pubkey_bytes, overwrite=True)
-
-        mock_set_coldkeypub.assert_called_once()
-        keypair: keyfile.Keypair = mock_set_coldkeypub.call_args_list[0][0][0]
-        assert keypair.public_key == pubkey_bytes
-
-
+#
+# def test_regen_coldkeypub_from_ss58_addr(mock_wallet):
+#     """Test the `regenerate_coldkeypub` method of the wallet class, which regenerates the cold key pair from an SS58 address.
+#     It checks whether the `set_coldkeypub` method is called with the expected arguments, and verifies that the generated key pair's SS58 address matches the input SS58 address.
+#     It also tests the behavior when an invalid SS58 address is provided, raising a `ValueError` as expected.
+#     """
+#     ss58_address = "5DD26kC2kxajmwfbbZmVmxhrY9VeeyR1Gpzy9i8wxLUg6zxm"
+#     with patch.object(mock_wallet, "set_coldkeypub") as mock_set_coldkeypub:
+#         mock_wallet.regenerate_coldkeypub(ss58_address=ss58_address, overwrite=True)
+#
+#         mock_set_coldkeypub.assert_called_once()
+#         keypair: keyfile.Keypair = mock_set_coldkeypub.call_args_list[0][0][0]
+#         assert keypair.ss58_address == ss58_address
+#
+#     ss58_address_bad = (
+#         "5DD26kC2kxajmwfbbZmVmxhrY9VeeyR1Gpzy9i8wxLUg6zx"  # 1 character short
+#     )
+#     with pytest.raises(ValueError):
+#         mock_wallet.regenerate_coldkeypub(ss58_address=ss58_address_bad, overwrite=True)
+#
+#
+# def test_regen_coldkeypub_from_hex_pubkey_str(mock_wallet):
+#     """Test the `regenerate_coldkeypub` method of the wallet class, which regenerates the cold key pair from a hex public key string.
+#     It checks whether the `set_coldkeypub` method is called with the expected arguments, and verifies that the generated key pair's public key matches the input public key.
+#     It also tests the behavior when an invalid public key string is provided, raising a `ValueError` as expected.
+#     """
+#     pubkey_str = "0x32939b6abc4d81f02dff04d2b8d1d01cc8e71c5e4c7492e4fa6a238cdca3512f"
+#     with patch.object(mock_wallet, "set_coldkeypub") as mock_set_coldkeypub:
+#         mock_wallet.regenerate_coldkeypub(public_key=pubkey_str, overwrite=True)
+#
+#         mock_set_coldkeypub.assert_called_once()
+#         keypair: keyfile.Keypair = mock_set_coldkeypub.call_args_list[0][0][0]
+#         assert "0x" + keypair.public_key.hex() == pubkey_str
+#
+#     pubkey_str_bad = "0x32939b6abc4d81f02dff04d2b8d1d01cc8e71c5e4c7492e4fa6a238cdca3512"  # 1 character short
+#     with pytest.raises(ValueError):
+#         mock_wallet.regenerate_coldkeypub(ss58_address=pubkey_str_bad, overwrite=True)
+#
+#
+# def test_regen_coldkeypub_from_hex_pubkey_bytes(mock_wallet):
+#     """Test the `regenerate_coldkeypub` method of the wallet class, which regenerates the cold key pair from a hex public key byte string.
+#     It checks whether the `set_coldkeypub` method is called with the expected arguments, and verifies that the generated key pair's public key matches the input public key.
+#     """
+#     pubkey_str = "0x32939b6abc4d81f02dff04d2b8d1d01cc8e71c5e4c7492e4fa6a238cdca3512f"
+#     pubkey_bytes = bytes.fromhex(pubkey_str[2:])  # Remove 0x from beginning
+#     with patch.object(mock_wallet, "set_coldkeypub") as mock_set_coldkeypub:
+#         mock_wallet.regenerate_coldkeypub(public_key=pubkey_bytes, overwrite=True)
+#
+#         mock_set_coldkeypub.assert_called_once()
+#         keypair: keyfile.Keypair = mock_set_coldkeypub.call_args_list[0][0][0]
+#         assert keypair.public_key == pubkey_bytes
+#
+#
 def test_regen_coldkeypub_no_pubkey(mock_wallet):
     """Test the `regenerate_coldkeypub` method of the wallet class when no public key is provided.
     It verifies that a `ValueError` is raised when neither a public key nor an SS58 address is provided.
@@ -336,172 +334,173 @@ def test_regen_coldkeypub_no_pubkey(mock_wallet):
         )
 
 
-def test_regen_coldkey_from_hex_seed_str(mock_wallet):
-    """Test the `regenerate_coldkey` method of the wallet class, which regenerates the cold key pair from a hex seed string.
-    It checks whether the `set_coldkey` method is called with the expected arguments, and verifies that the generated key pair's seed and SS58 address match the input seed and the expected SS58 address.
-    It also tests the behavior when an invalid seed string is provided, raising a `ValueError` as expected.
-    """
-    ss58_addr = "5D5cwd8DX6ij7nouVcoxDuWtJfiR1BnzCkiBVTt7DU8ft5Ta"
-    seed_str = "0x659c024d5be809000d0d93fe378cfde020846150b01c49a201fc2a02041f7636"
-    with patch.object(mock_wallet, "set_coldkey") as mock_set_coldkey:
-        mock_wallet.regenerate_coldkey(seed=seed_str, overwrite=True, suppress=True)
-
-        mock_set_coldkey.assert_called_once()
-        keypair: keyfile.Keypair = mock_set_coldkey.call_args_list[0][0][0]
-        seed_hex = (
-            keypair.seed_hex
-            if isinstance(keypair.seed_hex, str)
-            else keypair.seed_hex.hex()
-        )
-
-        assert re.match(
-            rf"(0x|){seed_str[2:]}", seed_hex
-        ), "The seed_hex does not match the expected pattern"
-        assert (
-            keypair.ss58_address == ss58_addr
-        )  # Check that the ss58 address is correct
-
-    seed_str_bad = "0x659c024d5be809000d0d93fe378cfde020846150b01c49a201fc2a02041f763"  # 1 character short
-    with pytest.raises(ValueError):
-        mock_wallet.regenerate_coldkey(seed=seed_str_bad, overwrite=True, suppress=True)
-
-
-def test_regen_hotkey_from_hex_seed_str(mock_wallet):
-    """Test the `regenerate_coldkey` method of the wallet class, which regenerates the cold key pair from a hex seed string.
-    It checks whether the `set_coldkey` method is called with the expected arguments, and verifies that the generated key pair's seed and SS58 address match the input seed and the expected SS58 address.
-    It also tests the behavior when an invalid seed string is provided, raising a `ValueError` as expected.
-    """
-    ss58_addr = "5D5cwd8DX6ij7nouVcoxDuWtJfiR1BnzCkiBVTt7DU8ft5Ta"
-    seed_str = "0x659c024d5be809000d0d93fe378cfde020846150b01c49a201fc2a02041f7636"
-    with patch.object(mock_wallet, "set_hotkey") as mock_set_hotkey:
-        mock_wallet.regenerate_hotkey(seed=seed_str, overwrite=True, suppress=True)
-
-        mock_set_hotkey.assert_called_once()
-        keypair: keyfile.Keypair = mock_set_hotkey.call_args_list[0][0][0]
-
-        seed_hex = (
-            keypair.seed_hex
-            if isinstance(keypair.seed_hex, str)
-            else keypair.seed_hex.hex()
-        )
+#
+# def test_regen_coldkey_from_hex_seed_str(mock_wallet):
+#     """Test the `regenerate_coldkey` method of the wallet class, which regenerates the cold key pair from a hex seed string.
+#     It checks whether the `set_coldkey` method is called with the expected arguments, and verifies that the generated key pair's seed and SS58 address match the input seed and the expected SS58 address.
+#     It also tests the behavior when an invalid seed string is provided, raising a `ValueError` as expected.
+#     """
+#     ss58_addr = "5D5cwd8DX6ij7nouVcoxDuWtJfiR1BnzCkiBVTt7DU8ft5Ta"
+#     seed_str = "0x659c024d5be809000d0d93fe378cfde020846150b01c49a201fc2a02041f7636"
+#     with patch.object(mock_wallet, "set_coldkey") as mock_set_coldkey:
+#         mock_wallet.regenerate_coldkey(seed=seed_str, overwrite=True, suppress=True)
+#
+#         mock_set_coldkey.assert_called_once()
+#         keypair: keyfile.Keypair = mock_set_coldkey.call_args_list[0][0][0]
+#         seed_hex = (
+#             keypair.seed_hex
+#             if isinstance(keypair.seed_hex, str)
+#             else keypair.seed_hex.hex()
+#         )
+#
+#         assert re.match(
+#             rf"(0x|){seed_str[2:]}", seed_hex
+#         ), "The seed_hex does not match the expected pattern"
+#         assert (
+#             keypair.ss58_address == ss58_addr
+#         )  # Check that the ss58 address is correct
+#
+#     seed_str_bad = "0x659c024d5be809000d0d93fe378cfde020846150b01c49a201fc2a02041f763"  # 1 character short
+#     with pytest.raises(ValueError):
+#         mock_wallet.regenerate_coldkey(seed=seed_str_bad, overwrite=True, suppress=True)
+#
 
-        pattern = rf"(0x|){seed_str[2:]}"
-        assert re.match(
-            pattern, seed_hex
-        ), f"The seed_hex '{seed_hex}' does not match the expected pattern '{pattern}'"
-        assert (
-            keypair.ss58_address == ss58_addr
-        )  # Check that the ss58 address is correct
+# def test_regen_hotkey_from_hex_seed_str(mock_wallet):
+#     """Test the `regenerate_coldkey` method of the wallet class, which regenerates the cold key pair from a hex seed string.
+#     It checks whether the `set_coldkey` method is called with the expected arguments, and verifies that the generated key pair's seed and SS58 address match the input seed and the expected SS58 address.
+#     It also tests the behavior when an invalid seed string is provided, raising a `ValueError` as expected.
+#     """
+#     ss58_addr = "5D5cwd8DX6ij7nouVcoxDuWtJfiR1BnzCkiBVTt7DU8ft5Ta"
+#     seed_str = "0x659c024d5be809000d0d93fe378cfde020846150b01c49a201fc2a02041f7636"
+#     with patch.object(mock_wallet, "set_hotkey") as mock_set_hotkey:
+#         mock_wallet.regenerate_hotkey(seed=seed_str, overwrite=True, suppress=True)
+#
+#         mock_set_hotkey.assert_called_once()
+#         keypair: keyfile.Keypair = mock_set_hotkey.call_args_list[0][0][0]
+#
+#         seed_hex = (
+#             keypair.seed_hex
+#             if isinstance(keypair.seed_hex, str)
+#             else keypair.seed_hex.hex()
+#         )
+#
+#         pattern = rf"(0x|){seed_str[2:]}"
+#         assert re.match(
+#             pattern, seed_hex
+#         ), f"The seed_hex '{seed_hex}' does not match the expected pattern '{pattern}'"
+#         assert (
+#             keypair.ss58_address == ss58_addr
+#         )  # Check that the ss58 address is correct
+#
+#     seed_str_bad = "0x659c024d5be809000d0d93fe378cfde020846150b01c49a201fc2a02041f763"  # 1 character short
+#     with pytest.raises(ValueError):
+#         mock_wallet.regenerate_hotkey(seed=seed_str_bad, overwrite=True, suppress=True)
+#
 
-    seed_str_bad = "0x659c024d5be809000d0d93fe378cfde020846150b01c49a201fc2a02041f763"  # 1 character short
-    with pytest.raises(ValueError):
-        mock_wallet.regenerate_hotkey(seed=seed_str_bad, overwrite=True, suppress=True)
-
-
-@pytest.mark.parametrize(
-    "mnemonic, expected_exception",
-    [
-        # Input is in a string format
-        (
-            "fiscal prevent noise record smile believe quote front weasel book axis legal",
-            None,
-        ),
-        # Input is in a list format (acquired by encapsulating mnemonic arg in a string "" in the cli)
-        (
-            [
-                "fiscal prevent noise record smile believe quote front weasel book axis legal"
-            ],
-            None,
-        ),
-        # Input is in a full list format (aquired by pasting mnemonic arg simply w/o quotes in cli)
-        (
-            [
-                "fiscal",
-                "prevent",
-                "noise",
-                "record",
-                "smile",
-                "believe",
-                "quote",
-                "front",
-                "weasel",
-                "book",
-                "axis",
-                "legal",
-            ],
-            None,
-        ),
-        # Incomplete mnemonic
-        ("word1 word2 word3", ValueError),
-        # No mnemonic added
-        (None, ValueError),
-    ],
-    ids=[
-        "string-format",
-        "list-format-thru-string",
-        "list-format",
-        "incomplete-mnemonic",
-        "no-mnemonic",
-    ],
-)
-def test_regen_coldkey_mnemonic(mock_wallet, mnemonic, expected_exception):
-    """Test the `regenerate_coldkey` method of the wallet class, which regenerates the cold key pair from a mnemonic.
-    We test different input formats of mnemonics and check if the function works as expected.
-    """
-    with patch.object(mock_wallet, "set_coldkey") as mock_set_coldkey, patch.object(
-        mock_wallet, "set_coldkeypub"
-    ) as mock_set_coldkeypub:
-        if expected_exception:
-            with pytest.raises(expected_exception):
-                mock_wallet.regenerate_coldkey(
-                    mnemonic=mnemonic, overwrite=True, suppress=True
-                )
-        else:
-            mock_wallet.regenerate_coldkey(mnemonic=mnemonic)
-            mock_set_coldkey.assert_called_once()
-            mock_set_coldkeypub.assert_called_once()
-
-
-@pytest.mark.parametrize(
-    "overwrite, user_input, expected_exception",
-    [
-        (True, None, None),  # Test with overwrite=True, no user input needed
-        (False, "n", True),  # Test with overwrite=False and user says no, KeyFileError
-        (False, "y", None),  # Test with overwrite=False and user says yes
-    ],
-)
-def test_regen_coldkey_overwrite_functionality(
-    mock_wallet, overwrite, user_input, expected_exception
-):
-    """Test the `regenerate_coldkey` method of the wallet class, emphasizing on the overwrite functionality"""
-    ss58_addr = "5D5cwd8DX6ij7nouVcoxDuWtJfiR1BnzCkiBVTt7DU8ft5Ta"
-    seed_str = "0x659c024d5be809000d0d93fe378cfde020846150b01c49a201fc2a02041f7636"
-
-    with patch.object(mock_wallet, "set_coldkey") as mock_set_coldkey, patch(
-        "builtins.input", return_value=user_input
-    ):
-        if expected_exception:
-            with pytest.raises(KeyFileError):
-                mock_wallet.regenerate_coldkey(
-                    seed=seed_str, overwrite=overwrite, suppress=True
-                )
-        else:
-            mock_wallet.regenerate_coldkey(
-                seed=seed_str, overwrite=overwrite, suppress=True
-            )
-            mock_set_coldkey.assert_called_once()
-            keypair = mock_set_coldkey.call_args_list[0][0][0]
-            seed_hex = (
-                keypair.seed_hex
-                if isinstance(keypair.seed_hex, str)
-                else keypair.seed_hex.hex()
-            )
-            assert re.match(
-                rf"(0x|){seed_str[2:]}", seed_hex
-            ), "The seed_hex does not match the expected pattern"
-            assert (
-                keypair.ss58_address == ss58_addr
-            ), "The SS58 address does not match the expected address"
+# @pytest.mark.parametrize(
+#     "mnemonic, expected_exception",
+#     [
+#         # Input is in a string format
+#         (
+#             "fiscal prevent noise record smile believe quote front weasel book axis legal",
+#             None,
+#         ),
+#         # Input is in a list format (acquired by encapsulating mnemonic arg in a string "" in the cli)
+#         (
+#             [
+#                 "fiscal prevent noise record smile believe quote front weasel book axis legal"
+#             ],
+#             None,
+#         ),
+#         # Input is in a full list format (aquired by pasting mnemonic arg simply w/o quotes in cli)
+#         (
+#             [
+#                 "fiscal",
+#                 "prevent",
+#                 "noise",
+#                 "record",
+#                 "smile",
+#                 "believe",
+#                 "quote",
+#                 "front",
+#                 "weasel",
+#                 "book",
+#                 "axis",
+#                 "legal",
+#             ],
+#             None,
+#         ),
+#         # Incomplete mnemonic
+#         ("word1 word2 word3", ValueError),
+#         # No mnemonic added
+#         (None, ValueError),
+#     ],
+#     ids=[
+#         "string-format",
+#         "list-format-thru-string",
+#         "list-format",
+#         "incomplete-mnemonic",
+#         "no-mnemonic",
+#     ],
+# )
+# def test_regen_coldkey_mnemonic(mock_wallet, mnemonic, expected_exception):
+#     """Test the `regenerate_coldkey` method of the wallet class, which regenerates the cold key pair from a mnemonic.
+#     We test different input formats of mnemonics and check if the function works as expected.
+#     """
+#     with patch.object(mock_wallet, "set_coldkey") as mock_set_coldkey, patch.object(
+#         mock_wallet, "set_coldkeypub"
+#     ) as mock_set_coldkeypub:
+#         if expected_exception:
+#             with pytest.raises(expected_exception):
+#                 mock_wallet.regenerate_coldkey(
+#                     mnemonic=mnemonic, overwrite=True, suppress=True
+#                 )
+#         else:
+#             mock_wallet.regenerate_coldkey(mnemonic=mnemonic)
+#             mock_set_coldkey.assert_called_once()
+#             mock_set_coldkeypub.assert_called_once()
+
+
+# @pytest.mark.parametrize(
+#     "overwrite, user_input, expected_exception",
+#     [
+#         (True, None, None),  # Test with overwrite=True, no user input needed
+#         (False, "n", True),  # Test with overwrite=False and user says no, KeyFileError
+#         (False, "y", None),  # Test with overwrite=False and user says yes
+#     ],
+# )
+# def test_regen_coldkey_overwrite_functionality(
+#     mock_wallet, overwrite, user_input, expected_exception
+# ):
+#     """Test the `regenerate_coldkey` method of the wallet class, emphasizing on the overwrite functionality"""
+#     ss58_addr = "5D5cwd8DX6ij7nouVcoxDuWtJfiR1BnzCkiBVTt7DU8ft5Ta"
+#     seed_str = "0x659c024d5be809000d0d93fe378cfde020846150b01c49a201fc2a02041f7636"
+#
+#     with patch.object(mock_wallet, "set_coldkey") as mock_set_coldkey, patch(
+#         "builtins.input", return_value=user_input
+#     ):
+#         if expected_exception:
+#             with pytest.raises(KeyFileError):
+#                 mock_wallet.regenerate_coldkey(
+#                     seed=seed_str, overwrite=overwrite, suppress=True
+#                 )
+#         else:
+#             mock_wallet.regenerate_coldkey(
+#                 seed=seed_str, overwrite=overwrite, suppress=True
+#             )
+#             mock_set_coldkey.assert_called_once()
+#             keypair = mock_set_coldkey.call_args_list[0][0][0]
+#             seed_hex = (
+#                 keypair.seed_hex
+#                 if isinstance(keypair.seed_hex, str)
+#                 else keypair.seed_hex.hex()
+#             )
+#             assert re.match(
+#                 rf"(0x|){seed_str[2:]}", seed_hex
+#             ), "The seed_hex does not match the expected pattern"
+#             assert (
+#                 keypair.ss58_address == ss58_addr
+#             ), "The SS58 address does not match the expected address"
 
 
 def test_unlock_hotkey(mock_wallet):
@@ -509,9 +508,13 @@ def test_unlock_hotkey(mock_wallet):
 
     # Call
     result = mock_wallet.unlock_hotkey()
-
     # Assertions
-    assert result == mock_wallet.hotkey
+    assert result.ss58_address == mock_wallet.get_hotkey().ss58_address
+    assert result.public_key == mock_wallet.get_hotkey().public_key
+    assert result.ss58_format == mock_wallet.get_hotkey().ss58_format
+    assert result.seed_hex == mock_wallet.get_hotkey().seed_hex
+    assert result.crypto_type == mock_wallet.get_hotkey().crypto_type
+    assert result.mnemonic == mock_wallet.get_hotkey().mnemonic
 
 
 def test_unlock_coldkey(mock_wallet):
@@ -519,16 +522,23 @@ def test_unlock_coldkey(mock_wallet):
 
     # Call
     result = mock_wallet.unlock_coldkey()
-
     # Assertions
-    assert result == mock_wallet.coldkey
+    assert result.ss58_address == mock_wallet.get_coldkey().ss58_address
+    assert result.public_key == mock_wallet.get_coldkey().public_key
+    assert result.ss58_format == mock_wallet.get_coldkey().ss58_format
+    assert result.seed_hex == mock_wallet.get_coldkey().seed_hex
+    assert result.crypto_type == mock_wallet.get_coldkey().crypto_type
+    assert result.mnemonic == mock_wallet.get_coldkey().mnemonic
 
 
 def test_unlock_coldkeypub(mock_wallet):
     """Verify that `unlock_coldkeypub` works correctly."""
-
     # Call
     result = mock_wallet.unlock_coldkeypub()
-
     # Assertions
-    assert result == mock_wallet.coldkeypub
+    assert result.ss58_address == mock_wallet.get_coldkeypub().ss58_address
+    assert result.public_key == mock_wallet.get_coldkeypub().public_key
+    assert result.ss58_format == mock_wallet.get_coldkeypub().ss58_format
+    assert result.seed_hex == mock_wallet.get_coldkeypub().seed_hex
+    assert result.crypto_type == mock_wallet.get_coldkeypub().crypto_type
+    assert result.mnemonic == mock_wallet.get_coldkeypub().mnemonic