bittensor-wallet 2.0.2__tar.gz → 2.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/.circleci/config.yml +2 -0
  2. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/CHANGELOG.MD +3 -0
  3. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/Cargo.lock +11 -1
  4. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/Cargo.toml +2 -1
  5. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/PKG-INFO +2 -2
  6. bittensor_wallet-2.0.3/bittensor_wallet/__init__.py +16 -0
  7. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/errors/__init__.py +1 -0
  8. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/pyproject.toml +2 -2
  9. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/constants.rs +1 -1
  10. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/errors.rs +33 -1
  11. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/keyfile.rs +23 -27
  12. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/lib.rs +1 -0
  13. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/wallet.rs +23 -29
  14. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/tests/test_keyfile.py +0 -1
  15. bittensor_wallet-2.0.2/bittensor_wallet/__init__.py +0 -16
  16. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/.flake8 +0 -0
  17. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/.github/workflows/release.yml +0 -0
  18. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/.gitignore +0 -0
  19. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/LICENSE +0 -0
  20. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/README.md +0 -0
  21. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/RUST-README.md +0 -0
  22. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/keyfile/__init__.py +0 -0
  23. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/keypair/__init__.py +0 -0
  24. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/mock/__init__.py +0 -0
  25. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/mock/keyfile_mock.py +0 -0
  26. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/mock/wallet_mock.py +0 -0
  27. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/utils/__init__.py +0 -0
  28. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/wallet/__init__.py +0 -0
  29. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/requirements/dev.txt +0 -0
  30. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/requirements/prod.txt +0 -0
  31. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/config.rs +0 -0
  32. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/keypair.rs +0 -0
  33. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/utils.rs +0 -0
  34. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/tests/test_utils.py +0 -0
  35. {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/tests/test_wallet.py +0 -0
@@ -33,6 +33,8 @@ jobs:
33
33
  - run:
34
34
  name: Set Up Virtual Environment
35
35
  command: |
36
+ curl https://sh.rustup.rs -sSf | sh -s -- -y
37
+ . "$HOME/.cargo/env"
36
38
  python -m venv .venv
37
39
  . .venv/bin/activate
38
40
  python -m pip install --upgrade pip
@@ -5,6 +5,9 @@
5
5
  ## What's Changed
6
6
 
7
7
  * Add the ability to use environment variables to store hot/coldkey passwords by @roman-opentensor in https://github.com/opentensor/btwallet/pull/46
8
+ * Fix wallet paths outside userhome by @camfairchild in https://github.com/opentensor/btwallet/pull/59
9
+ * fix https://github.com/opentensor/btwallet/issues/51 by @camfairchild in https://github.com/opentensor/btwallet/pull/56
10
+ * password fixes by @roman-opentensor
8
11
  * fix/roman/fix-config-parsing by @roman-opentensor in https://github.com/opentensor/btwallet/pull/47
9
12
 
10
13
  **Full Changelog**: https://github.com/opentensor/btwallet/compare/v2.0.1...v2.0.2
@@ -352,7 +352,7 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
352
352
 
353
353
  [[package]]
354
354
  name = "bittensor_wallet"
355
- version = "2.0.0"
355
+ version = "2.0.3"
356
356
  dependencies = [
357
357
  "ansible-vault",
358
358
  "base64 0.22.1",
@@ -371,6 +371,7 @@ dependencies = [
371
371
  "serde",
372
372
  "serde_json",
373
373
  "sha2 0.10.8",
374
+ "shellexpand",
374
375
  "sodiumoxide",
375
376
  "sp-core",
376
377
  ]
@@ -2230,6 +2231,15 @@ dependencies = [
2230
2231
  "lazy_static",
2231
2232
  ]
2232
2233
 
2234
+ [[package]]
2235
+ name = "shellexpand"
2236
+ version = "3.1.0"
2237
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2238
+ checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b"
2239
+ dependencies = [
2240
+ "dirs",
2241
+ ]
2242
+
2233
2243
  [[package]]
2234
2244
  name = "shlex"
2235
2245
  version = "1.3.0"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "bittensor_wallet"
3
- version = "2.0.0"
3
+ version = "2.0.3"
4
4
  edition = "2021"
5
5
 
6
6
  [lib]
@@ -27,6 +27,7 @@ base64 = "0.22.1"
27
27
  scrypt = "0.11.0"
28
28
  pkcs8 = "0.10.2"
29
29
  schnorrkel = "0.11.4"
30
+ shellexpand = "3.1.0"
30
31
 
31
32
  [features]
32
33
  extension-module = ["pyo3/extension-module"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bittensor-wallet
3
- Version: 2.0.2
3
+ Version: 2.0.3
4
4
  Classifier: Development Status :: 5 - Production/Stable
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: Topic :: Software Development :: Build Tools
@@ -19,7 +19,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
19
  Requires-Dist: termcolor
20
20
  Requires-Dist: eth-utils <2.3.0
21
21
  Requires-Dist: password-strength
22
- Requires-Dist: cryptography ~=42.0.5
22
+ Requires-Dist: cryptography ~=43.0.1
23
23
  Requires-Dist: ansible ~=6.7
24
24
  Requires-Dist: ansible-vault ~=2.1
25
25
  Requires-Dist: munch ~=2.5.0
@@ -0,0 +1,16 @@
1
+ from bittensor_wallet.bittensor_wallet import (
2
+ # classes
3
+ Config as Config,
4
+ Keyfile as Keyfile,
5
+ Keypair as Keypair,
6
+ Wallet as Wallet,
7
+ # modules
8
+ config as config,
9
+ errors as errors,
10
+ keyfile as keyfile,
11
+ keypair as keypair,
12
+ utils as utils,
13
+ wallet as wallet,
14
+ )
15
+
16
+ __version__ = "2.0.0"
@@ -2,3 +2,4 @@ from bittensor_wallet.bittensor_wallet import errors as _
2
2
 
3
3
  ConfigurationError = _.ConfigurationError
4
4
  KeyFileError = _.KeyFileError
5
+ PasswordError = _.PasswordError
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bittensor-wallet"
3
- version = "2.0.2"
3
+ version = "2.0.3"
4
4
  description = ""
5
5
  readme = "README.md"
6
6
  license = {file = "LICENSE"}
@@ -10,7 +10,7 @@ dependencies = [
10
10
  "termcolor",
11
11
  "eth-utils<2.3.0",
12
12
  "password_strength",
13
- "cryptography~=42.0.5",
13
+ "cryptography~=43.0.1",
14
14
  "ansible~=6.7",
15
15
  "ansible_vault~=2.1",
16
16
  "munch~=2.5.0",
@@ -1,3 +1,3 @@
1
1
  pub const BT_WALLET_NAME: &str = "default";
2
2
  pub const BT_WALLET_HOTKEY: &str = "default";
3
- pub const BT_WALLET_PATH: &str = ".bittensor/wallets/";
3
+ pub const BT_WALLET_PATH: &str = "~/.bittensor/wallets/";
@@ -2,13 +2,14 @@ use pyo3::exceptions::PyException;
2
2
  use pyo3::prelude::*;
3
3
  use std::{error, fmt};
4
4
 
5
+ // KeyFileError
5
6
  #[pyclass(extends=PyException)]
6
7
  #[derive(Debug)]
7
8
  pub struct KeyFileError {
8
9
  pub message: String,
9
10
  }
10
11
 
11
- /// Error thrown when the keyfile is corrupt, non-writable, non-readable or the password used to decrypt is invalid.
12
+ /// Error thrown when the keyfile is corrupt, non-writable, non-readable.
12
13
  #[pymethods]
13
14
  impl KeyFileError {
14
15
  #[new]
@@ -31,6 +32,7 @@ impl fmt::Display for KeyFileError {
31
32
 
32
33
  impl error::Error for KeyFileError {}
33
34
 
35
+ // ConfigurationError
34
36
  #[pyclass(extends=PyException)]
35
37
  #[derive(Debug)]
36
38
  pub struct ConfigurationError {
@@ -59,3 +61,33 @@ impl fmt::Display for ConfigurationError {
59
61
  }
60
62
 
61
63
  impl error::Error for ConfigurationError {}
64
+
65
+ // PasswordError
66
+ #[pyclass(extends=PyException)]
67
+ #[derive(Debug)]
68
+ pub struct PasswordError {
69
+ pub message: String,
70
+ }
71
+
72
+ /// PasswordError occurs if the password used for decryption is invalid.
73
+ #[pymethods]
74
+ impl PasswordError {
75
+ #[new]
76
+ #[pyo3(signature = (message=None))]
77
+ pub fn new(message: Option<String>) -> Self {
78
+ let msg = message.unwrap_or_default();
79
+ PasswordError { message: msg }
80
+ }
81
+
82
+ pub fn __str__(&self) -> String {
83
+ self.message.clone()
84
+ }
85
+ }
86
+
87
+ impl fmt::Display for PasswordError {
88
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89
+ write!(f, "PasswordError: {}", self.message)
90
+ }
91
+ }
92
+
93
+ impl error::Error for PasswordError {}
@@ -9,7 +9,7 @@ use std::env;
9
9
  use std::fs;
10
10
  use std::io::{Read, Write};
11
11
  use std::os::unix::fs::PermissionsExt;
12
- use std::path::Path;
12
+ use std::path::PathBuf;
13
13
  use std::str::from_utf8;
14
14
 
15
15
  use ansible_vault::{decrypt_vault, encrypt_vault};
@@ -19,7 +19,7 @@ use passwords::analyzer;
19
19
  use passwords::scorer;
20
20
  use serde_json::json;
21
21
 
22
- use crate::errors::KeyFileError;
22
+ use crate::errors::{KeyFileError, PasswordError};
23
23
  use crate::keypair::Keypair;
24
24
  use crate::utils;
25
25
 
@@ -414,7 +414,7 @@ pub fn decrypt_keyfile_data(
414
414
  .ok_or(PyErr::new::<PyRuntimeError, _>("Invalid nonce."))?;
415
415
  let ciphertext = &data[secretbox::NONCEBYTES..];
416
416
  secretbox::open(ciphertext, &nonce, key)
417
- .map_err(|_| PyErr::new::<KeyFileError, _>("Wrong password for nacl decryption."))
417
+ .map_err(|_| PyErr::new::<PasswordError, _>("Wrong password for nacl decryption."))
418
418
  }
419
419
 
420
420
  // decrypt of keyfile_data with legacy way
@@ -428,7 +428,7 @@ pub fn decrypt_keyfile_data(
428
428
  let keyfile_data_str = from_utf8(keyfile_data)?;
429
429
  fernet
430
430
  .decrypt(keyfile_data_str)
431
- .map_err(|_| PyErr::new::<KeyFileError, _>("Wrong password for nacl decryption."))
431
+ .map_err(|_| PyErr::new::<PasswordError, _>("Wrong password for legacy decryption."))
432
432
  }
433
433
 
434
434
  let mut password = password;
@@ -453,21 +453,21 @@ pub fn decrypt_keyfile_data(
453
453
  if keyfile_data_is_encrypted_nacl(py, keyfile_data)? {
454
454
  let key = derive_key(password.as_bytes());
455
455
  let decrypted_data = nacl_decrypt(keyfile_data, &key)
456
- .map_err(|_| PyErr::new::<KeyFileError, _>("Wrong password for decryption."))?;
456
+ .map_err(|_| PyErr::new::<PasswordError, _>("Wrong password for decryption."))?;
457
457
  return Ok(PyBytes::new_bound(py, &decrypted_data).into_py(py));
458
458
  }
459
459
 
460
460
  // Ansible Vault decryption
461
461
  if keyfile_data_is_encrypted_ansible(py, keyfile_data)? {
462
462
  let decrypted_data = decrypt_vault(keyfile_data, password.as_str())
463
- .map_err(|_| PyErr::new::<KeyFileError, _>("Wrong password for decryption."))?;
463
+ .map_err(|_| PyErr::new::<PasswordError, _>("Wrong password for decryption."))?;
464
464
  return Ok(PyBytes::new_bound(py, &decrypted_data).into_py(py));
465
465
  }
466
466
 
467
467
  // Legacy decryption
468
468
  if keyfile_data_is_encrypted_legacy(py, keyfile_data)? {
469
469
  let decrypted_data = legacy_decrypt(&password, keyfile_data)
470
- .map_err(|_| PyErr::new::<KeyFileError, _>("Wrong password for decryption."))?;
470
+ .map_err(|_| PyErr::new::<PasswordError, _>("Wrong password for decryption."))?;
471
471
  return Ok(PyBytes::new_bound(py, &decrypted_data).into_py(py));
472
472
  }
473
473
 
@@ -498,10 +498,6 @@ fn encrypt_password(key: String, value: String) -> String {
498
498
  let encrypted_char = (c as u8) ^ (key.chars().nth(i % key.len()).unwrap() as u8);
499
499
  encrypted.push(encrypted_char as char);
500
500
  }
501
- println!(
502
- ">>> key: {}, value: {}, encrypted: {}",
503
- key, value, encrypted
504
- );
505
501
  encrypted
506
502
  }
507
503
 
@@ -519,6 +515,7 @@ fn decrypt_password(data: String, key: String) -> String {
519
515
  #[pyclass(subclass)]
520
516
  pub struct Keyfile {
521
517
  path: String,
518
+ _path: PathBuf,
522
519
  name: String,
523
520
  should_save_to_env: bool,
524
521
  }
@@ -528,10 +525,11 @@ impl Keyfile {
528
525
  #[new]
529
526
  #[pyo3(signature = (path, name=None, should_save_to_env=false))]
530
527
  pub fn new(path: String, name: Option<String>, should_save_to_env: bool) -> PyResult<Self> {
531
- let path = expand_tilde(&path);
528
+ let expanded_path: PathBuf = PathBuf::from(expand_tilde(&path));
532
529
  let name = name.unwrap_or_else(|| "Keyfile".to_string());
533
530
  Ok(Keyfile {
534
531
  path,
532
+ _path: expanded_path,
535
533
  name,
536
534
  should_save_to_env,
537
535
  })
@@ -653,9 +651,7 @@ impl Keyfile {
653
651
 
654
652
  /// Creates directories for the path if they do not exist.
655
653
  pub fn make_dirs(&self) -> PyResult<()> {
656
- // convert String to Path
657
- let path: &Path = self.path.as_ref();
658
- if let Some(directory) = path.parent() {
654
+ if let Some(directory) = self._path.parent() {
659
655
  // check if the dir is exit already
660
656
  if !directory.exists() {
661
657
  // create the dir if not
@@ -670,7 +666,7 @@ impl Keyfile {
670
666
  /// Returns:
671
667
  /// readable (bool): ``True`` if the file is readable.
672
668
  pub fn exists_on_device(&self) -> PyResult<bool> {
673
- Ok(Path::new(&self.path).exists())
669
+ Ok(self._path.exists())
674
670
  }
675
671
 
676
672
  /// Returns ``True`` if the file under path is readable.
@@ -681,7 +677,7 @@ impl Keyfile {
681
677
  }
682
678
 
683
679
  // get file metadata
684
- let metadata = fs::metadata(&self.path).map_err(|e| {
680
+ let metadata = fs::metadata(&self._path).map_err(|e| {
685
681
  PyErr::new::<PyIOError, _>(format!("Failed to get metadata for file: {}.", e))
686
682
  })?;
687
683
 
@@ -703,7 +699,7 @@ impl Keyfile {
703
699
  }
704
700
 
705
701
  // get file metadata
706
- let metadata = fs::metadata(&self.path).map_err(|e| {
702
+ let metadata = fs::metadata(&self._path).map_err(|e| {
707
703
  PyErr::new::<PyIOError, _>(format!("Failed to get metadata for file: {}", e))
708
704
  })?;
709
705
 
@@ -993,7 +989,7 @@ impl Keyfile {
993
989
  }
994
990
 
995
991
  // open and read the file
996
- let mut file = fs::File::open(&self.path)
992
+ let mut file = fs::File::open(&self._path)
997
993
  .map_err(|e| PyErr::new::<PyOSError, _>(format!("Failed to open file: {}.", e)))?;
998
994
  let mut data_vec = Vec::new();
999
995
  file.read_to_end(&mut data_vec)
@@ -1029,7 +1025,7 @@ impl Keyfile {
1029
1025
  .write(true)
1030
1026
  .create(true)
1031
1027
  .truncate(true) // cleanup if rewrite
1032
- .open(&self.path)
1028
+ .open(&self._path)
1033
1029
  .map_err(|e| PyErr::new::<PyIOError, _>(format!("Failed to open file: {}.", e)))?;
1034
1030
 
1035
1031
  // write data
@@ -1038,9 +1034,9 @@ impl Keyfile {
1038
1034
  .map_err(|e| PyErr::new::<PyIOError, _>(format!("Failed to write to file: {}.", e)))?;
1039
1035
 
1040
1036
  // set permissions
1041
- let mut permissions = fs::metadata(&self.path)?.permissions();
1037
+ let mut permissions = fs::metadata(&self._path)?.permissions();
1042
1038
  permissions.set_mode(0o600); // just for owner
1043
- fs::set_permissions(&self.path, permissions).map_err(|e| {
1039
+ fs::set_permissions(&self._path, permissions).map_err(|e| {
1044
1040
  PyErr::new::<PyPermissionError, _>(format!("Failed to set permissions: {}.", e))
1045
1041
  })?;
1046
1042
  Ok(())
@@ -1048,7 +1044,7 @@ impl Keyfile {
1048
1044
 
1049
1045
  /// Saves the key's password to the associated local environment variable.
1050
1046
  #[pyo3(signature = (password=None))]
1051
- fn save_password_to_env(&self, password: Option<String>, py: Python) -> PyResult<bool> {
1047
+ fn save_password_to_env(&self, password: Option<String>, py: Python) -> PyResult<String> {
1052
1048
  // checking the password
1053
1049
  let password = match password {
1054
1050
  Some(pwd) => pwd,
@@ -1056,7 +1052,7 @@ impl Keyfile {
1056
1052
  Ok(pwd) => pwd,
1057
1053
  Err(e) => {
1058
1054
  utils::print(format!("Error asking password: {:?}.\n", e));
1059
- return Ok(false);
1055
+ return Ok("".parse()?);
1060
1056
  }
1061
1057
  },
1062
1058
  };
@@ -1066,21 +1062,21 @@ impl Keyfile {
1066
1062
  // encrypt password
1067
1063
  let encrypted_password = encrypt_password(self.env_var_name()?, password);
1068
1064
  // store encrypted password
1069
- env::set_var(&env_var_name, encrypted_password);
1065
+ env::set_var(&env_var_name, &encrypted_password);
1070
1066
 
1071
1067
  let message = format!(
1072
1068
  "The password has been saved to environment variable '{}'.\n",
1073
1069
  env_var_name
1074
1070
  );
1075
1071
  utils::print(message);
1076
- Ok(true)
1072
+ Ok(encrypted_password)
1077
1073
  }
1078
1074
  Err(e) => {
1079
1075
  utils::print(format!(
1080
1076
  "Error saving environment variable name: {:?}.\n",
1081
1077
  e
1082
1078
  ));
1083
- Ok(false)
1079
+ Ok("".parse()?)
1084
1080
  }
1085
1081
  }
1086
1082
  }
@@ -36,6 +36,7 @@ fn register_errors_module(main_module: &Bound<'_, PyModule>) -> PyResult<()> {
36
36
  let errors_module = PyModule::new_bound(main_module.py(), "errors")?;
37
37
  errors_module.add_class::<errors::ConfigurationError>()?;
38
38
  errors_module.add_class::<errors::KeyFileError>()?;
39
+ errors_module.add_class::<errors::PasswordError>()?;
39
40
  main_module.add_submodule(&errors_module)
40
41
  }
41
42
 
@@ -4,6 +4,7 @@ use pyo3::types::{IntoPyDict, PyString, PyType};
4
4
 
5
5
  use colored::Colorize;
6
6
  use std::env;
7
+ use std::path::PathBuf;
7
8
 
8
9
  use crate::config::Config;
9
10
  use crate::constants::{BT_WALLET_HOTKEY, BT_WALLET_NAME, BT_WALLET_PATH};
@@ -12,10 +13,6 @@ use crate::keyfile::Keyfile;
12
13
  use crate::keypair::Keypair;
13
14
  use crate::utils::{self, is_valid_bittensor_address_or_public_key};
14
15
 
15
- use dirs::home_dir;
16
-
17
- type PyRuntimeError = KeyFileError;
18
-
19
16
  /// Display the mnemonic and a warning message to keep the mnemonic safe.
20
17
  #[pyfunction]
21
18
  #[pyo3(signature = (mnemonic, key_type))]
@@ -34,7 +31,11 @@ pub fn display_mnemonic_msg(mnemonic: String, key_type: &str) {
34
31
  }
35
32
 
36
33
  // Function to safely retrieve attribute as Option<String> from passed python object
37
- fn get_attribute_string(py: Python, obj: &Bound<PyAny>, attr_name: &str) -> PyResult<Option<String>> {
34
+ fn get_attribute_string(
35
+ py: Python,
36
+ obj: &Bound<PyAny>,
37
+ attr_name: &str,
38
+ ) -> PyResult<Option<String>> {
38
39
  match obj.getattr(attr_name) {
39
40
  Ok(attr) => {
40
41
  if attr.is_none() {
@@ -61,6 +62,8 @@ pub struct Wallet {
61
62
  pub path: String,
62
63
  pub hotkey: String,
63
64
 
65
+ _path: PathBuf,
66
+
64
67
  _coldkey: Option<Keypair>,
65
68
  _coldkeypub: Option<Keypair>,
66
69
  _hotkey: Option<Keypair>,
@@ -82,9 +85,8 @@ impl Wallet {
82
85
  hotkey: Option<String>,
83
86
  path: Option<String>,
84
87
  config: Option<PyObject>,
85
- py: Python
88
+ py: Python,
86
89
  ) -> PyResult<Wallet> {
87
-
88
90
  // default config's values if config and config.wallet exist
89
91
  let mut conf_name: Option<String> = None;
90
92
  let mut conf_hotkey: Option<String> = None;
@@ -128,15 +130,19 @@ impl Wallet {
128
130
  let final_path = if let Some(path) = path {
129
131
  path
130
132
  } else if let Some(conf_path) = conf_path {
131
- conf_path.strip_prefix("~/").unwrap_or(&conf_path).to_string()
133
+ conf_path
132
134
  } else {
133
135
  BT_WALLET_PATH.to_string()
134
136
  };
135
137
 
138
+ let expanded_path: PathBuf = PathBuf::from(shellexpand::tilde(&final_path).to_string());
139
+
136
140
  Ok(Wallet {
137
141
  name: final_name,
138
142
  hotkey: final_hotkey,
139
- path: final_path,
143
+ path: final_path.clone(),
144
+
145
+ _path: expanded_path,
140
146
 
141
147
  _coldkey: None,
142
148
  _coldkeypub: None,
@@ -146,14 +152,14 @@ impl Wallet {
146
152
 
147
153
  fn __str__(&self) -> PyResult<String> {
148
154
  Ok(format!(
149
- "Wallet (Name: '{:}', Hotkey: '{:}', Path: '~/{:}')",
155
+ "Wallet (Name: '{:}', Hotkey: '{:}', Path: '{:}')",
150
156
  self.name, self.hotkey, self.path
151
157
  ))
152
158
  }
153
159
 
154
160
  fn __repr__(&self) -> PyResult<String> {
155
161
  Ok(format!(
156
- "name: '{:}', hotkey: '{:}', path: '~/{:}'",
162
+ "name: '{:}', hotkey: '{:}', path: '{:}'",
157
163
  self.name, self.hotkey, self.path
158
164
  ))
159
165
  }
@@ -183,8 +189,8 @@ impl Wallet {
183
189
  env::var("BT_WALLET_NAME").unwrap_or_else(|_| BT_WALLET_NAME.to_string());
184
190
  let default_hotkey =
185
191
  env::var("BT_WALLET_HOTKEY").unwrap_or_else(|_| BT_WALLET_HOTKEY.to_string());
186
- let default_path =
187
- env::var("BT_WALLET_PATH").unwrap_or_else(|_| format!("~/{}", BT_WALLET_PATH.to_string()));
192
+ let default_path = env::var("BT_WALLET_PATH")
193
+ .unwrap_or_else(|_| format!("~/{}", BT_WALLET_PATH.to_string()));
188
194
 
189
195
  let prefix_str = if let Some(value) = prefix {
190
196
  format!("\"{}\"", value)
@@ -383,12 +389,8 @@ except argparse.ArgumentError:
383
389
  /// Created Hot Keyfile for Keypair
384
390
  #[pyo3(signature = (save_hotkey_to_env=false))]
385
391
  pub fn create_hotkey_file(&self, save_hotkey_to_env: bool) -> PyResult<Keyfile> {
386
- // get home dir
387
- let home = home_dir()
388
- .ok_or_else(|| PyErr::new::<PyRuntimeError, _>("Failed to get user home directory."))?;
389
-
390
392
  // concatenate wallet path
391
- let wallet_path = home.join(&self.path).join(&self.name);
393
+ let wallet_path = self._path.join(&self.name);
392
394
 
393
395
  // concatenate hotkey path
394
396
  let hotkey_path = wallet_path.join("hotkeys").join(&self.hotkey);
@@ -409,12 +411,8 @@ except argparse.ArgumentError:
409
411
  /// Created Cold Keyfile for Keypair
410
412
  #[pyo3(signature = (save_coldkey_to_env=false))]
411
413
  pub fn create_coldkey_file(&self, save_coldkey_to_env: bool) -> PyResult<Keyfile> {
412
- // get home dir
413
- let home = home_dir()
414
- .ok_or_else(|| PyErr::new::<PyRuntimeError, _>("Failed to get user home directory."))?;
415
-
416
414
  // concatenate wallet path
417
- let wallet_path = home.join(&self.path).join(&self.name);
415
+ let wallet_path = PathBuf::from(&self._path).join(&self.name);
418
416
 
419
417
  // concatenate coldkey path
420
418
  let coldkey_path = wallet_path.join("coldkey");
@@ -428,12 +426,8 @@ except argparse.ArgumentError:
428
426
  /// Property that returns the coldkeypub file.
429
427
  #[getter]
430
428
  pub fn coldkeypub_file(&self) -> PyResult<Keyfile> {
431
- // get home dir
432
- let home = home_dir()
433
- .ok_or_else(|| PyErr::new::<PyRuntimeError, _>("Failed to get user home directory."))?;
434
-
435
429
  // concatenate wallet path
436
- let wallet_path = home.join(&self.path).join(&self.name);
430
+ let wallet_path = self._path.join(&self.name);
437
431
 
438
432
  // concatenate hotkey path
439
433
  let coldkeypub_path = wallet_path.join("coldkeypub.txt");
@@ -828,7 +822,7 @@ except argparse.ArgumentError:
828
822
 
829
823
  let keypair = Keypair::new(ss58_address, public_key, None, 42, None, 1)?;
830
824
 
831
- self.set_coldkeypub(keypair, overwrite, false, py)?;
825
+ self.set_coldkeypub(keypair, false, overwrite, py)?;
832
826
  Ok(self.clone())
833
827
  }
834
828
 
@@ -23,7 +23,6 @@ from unittest import mock
23
23
 
24
24
  import pytest
25
25
  from bip39 import bip39_validate
26
- from jedi.common import monkeypatch
27
26
 
28
27
  from bittensor_wallet.errors import ConfigurationError, KeyFileError
29
28
  from bittensor_wallet.keyfile import Keyfile
@@ -1,16 +0,0 @@
1
- from bittensor_wallet.bittensor_wallet import (
2
- # classes
3
- Config,
4
- Keyfile,
5
- Keypair,
6
- Wallet,
7
- # modules
8
- config,
9
- errors,
10
- keyfile,
11
- keypair,
12
- utils,
13
- wallet,
14
- )
15
-
16
- __version__ = "2.0.0"