You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

bittensor-wallet

Package Overview
Dependencies
Maintainers
1
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bittensor-wallet - pypi Package Compare versions

Comparing version
3.0.11
to
3.1.0
+18
-0
bittensor_wallet/wallet/__init__.pyi

@@ -55,2 +55,3 @@ from typing import Any, Optional

def get_hotkey(self, password: Optional[str] = None) -> "Keypair": ...
def get_hotkeypub(self, password: Optional[str] = None) -> "Keypair": ...
def set_coldkey(

@@ -78,2 +79,8 @@ self,

) -> None: ...
def set_hotkeypub(
self,
keypair: "Keypair",
encrypt: bool = False,
overwrite: bool = False,
) -> None: ...
@property

@@ -86,2 +93,4 @@ def coldkey(self) -> "Keypair": ...

@property
def hotkeypub(self) -> "Keypair": ...
@property
def coldkey_file(self) -> "Keyfile": ...

@@ -93,2 +102,4 @@ @property

@property
def hotkeypub_file(self) -> "Keyfile": ...
@property
def name(self) -> str: ...

@@ -120,2 +131,3 @@ @property

def unlock_hotkey(self) -> "Keypair": ...
def unlock_hotkeypub(self) -> "Keypair": ...
def new_coldkey(

@@ -185,1 +197,7 @@ self,

) -> "Wallet": ...
def regenerate_hotkeypub(
self,
ss58_address: Optional[str] = None,
public_key: Optional[bytes] = None,
overwrite: Optional[bool] = False,
) -> "Wallet": ...
+1
-1
[package]
name = "bittensor_wallet"
version = "3.0.11"
version = "3.1.0"
edition = "2021"

@@ -5,0 +5,0 @@

# Changelog
## 3.1.0 /2025-07-07
## What's Changed
* Add `hotkeypub` to bittensor-wallet by @basfroman in https://github.com/opentensor/btwallet/pull/156
**Full Changelog**: https://github.com/opentensor/btwallet/compare/v3.0.11...v3.1.0
## 3.0.11 /2025-06-26

@@ -4,0 +11,0 @@

Metadata-Version: 2.4
Name: bittensor-wallet
Version: 3.0.11
Version: 3.1.0
Classifier: Development Status :: 5 - Production/Stable

@@ -5,0 +5,0 @@ Classifier: Intended Audience :: Developers

@@ -480,3 +480,3 @@ use std::{borrow::Cow, env, str};

module.add_class::<Wallet>()?;
// Add submodules to the main module

@@ -1004,2 +1004,11 @@ register_config_module(&module)?;

#[pyo3(signature = (password=None))]
fn get_hotkeypub(&self, password: Option<String>) -> PyResult<PyKeypair> {
let keypair = self
.inner
.get_hotkeypub(password)
.map_err(|e| PyErr::new::<PyKeyFileError, _>(e))?;
Ok(PyKeypair { inner: keypair })
}
#[pyo3(signature = (keypair, encrypt=true, overwrite=false, save_coldkey_to_env=false, coldkey_password=None))]

@@ -1057,2 +1066,14 @@ fn set_coldkey(

#[pyo3(signature = (keypair, encrypt=false, overwrite=false))]
fn set_hotkeypub(
&mut self,
keypair: PyKeypair,
encrypt: bool,
overwrite: bool,
) -> PyResult<()> {
self.inner
.set_hotkeypub(keypair.inner, encrypt, overwrite)
.map_err(|e| PyErr::new::<PyKeyFileError, _>(e))
}
// Getters

@@ -1083,2 +1104,10 @@ #[getter(coldkey)]

#[getter(hotkeypub)]
fn hotkeypub_py_property(&self) -> PyResult<PyKeypair> {
let keypair = self.inner.hotkeypub_property().map_err(|e| {
PyErr::new::<PyKeyFileError, _>(format!("Failed to get hotkeypub: {:?}", e))
})?;
Ok(PyKeypair { inner: keypair })
}
#[getter]

@@ -1109,2 +1138,10 @@ fn coldkey_file(&self) -> PyResult<PyKeyfile> {

#[getter]
fn hotkeypub_file(&self) -> PyResult<PyKeyfile> {
self.inner
.hotkeypub_file()
.map(|inner| PyKeyfile { inner })
.map_err(|e| PyErr::new::<PyKeyFileError, _>(e))
}
#[getter]
fn name(&self) -> String {

@@ -1226,2 +1263,16 @@ self.inner.get_name()

#[pyo3(text_signature = "($self)")]
fn unlock_hotkeypub(&mut self) -> PyResult<PyKeypair> {
self.inner
.unlock_hotkeypub()
.map(|inner| PyKeypair { inner })
.map_err(|e| match e {
KeyFileError::DecryptionError(_) => PyErr::new::<PyPasswordError, _>(format!(
"Decryption failed: {}",
e.to_string()
)),
_ => PyErr::new::<PyKeyFileError, _>(format!("Failed to unlock hotkey: {:?}", e)),
})
}
#[pyo3(

@@ -1386,2 +1437,19 @@ name = "create_new_coldkey",

}
#[pyo3(signature = (ss58_address=None, public_key=None, overwrite=None))]
fn regenerate_hotkeypub(
&mut self,
ss58_address: Option<String>,
public_key: Option<String>,
overwrite: Option<bool>,
) -> PyResult<Self> {
let new_inner_wallet = self
.inner
.regenerate_hotkeypub(ss58_address, public_key, overwrite.unwrap_or(false))
.map_err(|e| PyErr::new::<PyKeyFileError, _>(e))?;
self.inner = new_inner_wallet;
Ok(Wallet {
inner: self.inner.clone(),
})
}
}

@@ -40,2 +40,3 @@ use colored::Colorize;

_hotkey: Option<Keypair>,
_hotkeypub: Option<Keypair>,
}

@@ -99,2 +100,3 @@

_hotkey: None,
_hotkeypub: None,
}

@@ -151,3 +153,3 @@ }

/// Checks for existing coldkeypub and hotkeys, and creates them if non-existent.
/// Checks for existing coldkeypub, hotkeypub, hotkeys, and creates them if non-existent.
pub fn create_if_non_existent(

@@ -218,3 +220,6 @@ &mut self,

if overwrite || !self.hotkey_file()?.exists_on_device()? {
if overwrite
|| !self.hotkey_file()?.exists_on_device()?
&& !self.hotkeypub_file()?.exists_on_device()?
{
self.create_new_hotkey(

@@ -319,2 +324,16 @@ 12,

pub fn hotkeypub_file(&self) -> Result<Keyfile, KeyFileError> {
// concatenate wallet path
let wallet_path = self._path.join(&self.name);
// concatenate hotkeypub path
let hotkeypub_path = wallet_path.join("hotkeypub.txt");
Keyfile::new(
hotkeypub_path.to_string_lossy().into_owned(),
Some("hotkeypub.txt".to_string()),
false,
)
}
/// Returns the coldkeypub file.

@@ -361,2 +380,8 @@ pub fn coldkeypub_file(&self) -> Result<Keyfile, KeyFileError> {

/// Returns the hotkeypub from wallet.path/wallet.name/hotkeypub.txt or raises an error.
pub fn hotkeypub_property(&self) -> Result<Keypair, KeyFileError> {
let hotkeypub_file = self.hotkeypub_file()?;
hotkeypub_file.get_keypair(None)
}
/// Returns the name of the wallet

@@ -441,2 +466,23 @@ pub fn get_name(&self) -> String {

/// Sets the hotkeypub for the wallet.
pub fn set_hotkeypub(
&mut self,
keypair: Keypair,
encrypt: bool,
overwrite: bool,
) -> Result<(), KeyFileError> {
let ss58_address = keypair
.ss58_address()
.ok_or_else(|| KeyFileError::Generic("Failed to get ss58_address".to_string()))?;
let hotkeypub_keypair = Keypair::new(Some(ss58_address), None, None, 42, None, 1)
.map_err(|e| KeyFileError::Generic(e.to_string()))?;
self._hotkeypub = Some(hotkeypub_keypair.clone());
self.hotkeypub_file()
.map_err(|e| KeyFileError::Generic(e.to_string()))?
.set_keypair(hotkeypub_keypair, encrypt, overwrite, None)
.map_err(|e| KeyFileError::Generic(e.to_string()))?;
Ok(())
}
/// Gets the coldkey from the wallet.

@@ -457,2 +503,7 @@ pub fn get_coldkey(&self, password: Option<String>) -> Result<Keypair, KeyFileError> {

/// Gets the hotkeypub from the wallet.
pub fn get_hotkeypub(&self, password: Option<String>) -> Result<Keypair, KeyFileError> {
self.hotkeypub_file()?.get_keypair(password)
}
/// Creates coldkey from uri string, optionally encrypts it with the user-provided password.

@@ -514,2 +565,3 @@ pub fn create_coldkey_from_uri(

)?;
self.set_hotkeypub(keypair, false, overwrite)?;
Ok(self.clone())

@@ -557,2 +609,15 @@ }

/// Unlocks the hotkeypub.
pub fn unlock_hotkeypub(&mut self) -> Result<Keypair, KeyFileError> {
if self._hotkeypub.is_none() {
let hotkeypub_file = self.hotkeypub_file()?;
self._hotkeypub = Some(hotkeypub_file.get_keypair(None)?);
}
let _hotkeypub = self
._hotkeypub
.clone()
.ok_or_else(|| KeyFileError::Generic("Hotkey file doesn't exist.".to_string()))?;
Ok(_hotkeypub)
}
/// Creates a new coldkey, optionally encrypts it with the user-provided password and saves to disk.

@@ -665,39 +730,5 @@ pub fn new_coldkey(

)?;
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.
pub fn regenerate_coldkeypub(
&mut self,
ss58_address: Option<String>,
public_key: Option<String>,
overwrite: bool,
) -> Result<Self, WalletError> {
if ss58_address.is_none() && public_key.is_none() {
return Err(WalletError::InvalidInput(
"Either ss58_address or public_key must be passed.".to_string(),
));
}
self.set_hotkeypub(keypair.clone(), false, overwrite)?;
let address_to_string = ss58_address
.as_ref()
.or(public_key.as_ref())
.ok_or_else(|| WalletError::InvalidInput("No address provided".to_string()))?;
if !is_valid_bittensor_address_or_public_key(address_to_string) {
return Err(WalletError::InvalidInput(format!(
"Invalid {}.",
if ss58_address.is_some() {
"ss58_address"
} else {
"public_key"
}
)));
}
let keypair = Keypair::new(ss58_address, public_key, None, 42, None, 1)
.map_err(|e| WalletError::KeyGeneration(e.to_string()))?;
self.set_coldkeypub(keypair, false, overwrite)?;
Ok(self.clone())

@@ -752,2 +783,39 @@ }

/// 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.
pub fn regenerate_coldkeypub(
&mut self,
ss58_address: Option<String>,
public_key: Option<String>,
overwrite: bool,
) -> Result<Self, WalletError> {
if ss58_address.is_none() && public_key.is_none() {
return Err(WalletError::InvalidInput(
"Either ss58_address or public_key must be passed.".to_string(),
));
}
let address_to_string = ss58_address
.as_ref()
.or(public_key.as_ref())
.ok_or_else(|| WalletError::InvalidInput("No address provided".to_string()))?;
if !is_valid_bittensor_address_or_public_key(address_to_string) {
return Err(WalletError::InvalidInput(format!(
"Invalid {}.",
if ss58_address.is_some() {
"ss58_address"
} else {
"public_key"
}
)));
}
let keypair = Keypair::new(ss58_address, public_key, None, 42, None, 1)
.map_err(|e| WalletError::KeyGeneration(e.to_string()))?;
self.set_coldkeypub(keypair, false, overwrite)?;
Ok(self.clone())
}
/// Regenerates the hotkey from passed mnemonic or seed, encrypts it with the user's password and saves the file.

@@ -788,3 +856,3 @@ pub fn regenerate_hotkey(

self.set_hotkey(
keypair,
keypair.clone(),
use_password,

@@ -795,5 +863,42 @@ overwrite,

)?;
self.set_hotkeypub(keypair.clone(), false, overwrite)?;
Ok(self.clone())
}
/// Regenerates the hotkeypub from the passed ss58_address or public_key and saves the file.
/// Requires either ss58_address or public_key to be passed.
pub fn regenerate_hotkeypub(
&mut self,
ss58_address: Option<String>,
public_key: Option<String>,
overwrite: bool,
) -> Result<Self, WalletError> {
if ss58_address.is_none() && public_key.is_none() {
return Err(WalletError::InvalidInput(
"Either ss58_address or public_key must be passed.".to_string(),
));
}
let address_to_string = ss58_address
.as_ref()
.or(public_key.as_ref())
.ok_or_else(|| WalletError::InvalidInput("No address provided".to_string()))?;
if !is_valid_bittensor_address_or_public_key(address_to_string) {
return Err(WalletError::InvalidInput(format!(
"Invalid {}.",
if ss58_address.is_some() {
"ss58_address"
} else {
"public_key"
}
)));
}
let keypair = Keypair::new(ss58_address, public_key, None, 42, None, 1)
.map_err(|e| WalletError::KeyGeneration(e.to_string()))?;
self.set_hotkeypub(keypair, false, overwrite)?;
Ok(self.clone())
}
}

@@ -196,3 +196,2 @@ import argparse

# Decrypt data...
print(">>> kf.data", kf.data)
json_data = json.loads(kf.data)

@@ -199,0 +198,0 @@ assert set(json_data.keys()) == {

@@ -9,2 +9,3 @@ import json

from bittensor_wallet import Wallet, keyfile
from bittensor_wallet.errors import KeyFileError

@@ -158,10 +159,17 @@

# Call
result = mock_wallet.unlock_coldkeypub()
coldkeypub = mock_wallet.unlock_coldkeypub()
hotkeypub = mock_wallet.unlock_hotkeypub()
# Assertions
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.crypto_type == mock_wallet.get_coldkeypub().crypto_type
assert coldkeypub.ss58_address == mock_wallet.get_coldkeypub().ss58_address
assert coldkeypub.public_key == mock_wallet.get_coldkeypub().public_key
assert coldkeypub.ss58_format == mock_wallet.get_coldkeypub().ss58_format
assert coldkeypub.crypto_type == mock_wallet.get_coldkeypub().crypto_type
assert hotkeypub.ss58_address == mock_wallet.get_hotkeypub().ss58_address
assert hotkeypub.public_key == mock_wallet.get_hotkeypub().public_key
assert hotkeypub.ss58_format == mock_wallet.get_hotkeypub().ss58_format
assert hotkeypub.crypto_type == mock_wallet.get_hotkeypub().crypto_type
def test_wallet_string_representation_with_default_arguments():

@@ -232,1 +240,41 @@ """Tests wallet string representation with default arguments."""

assert w.coldkeypub.ss58_address is not None
def test_regenerate_hotkeypub(tmp_path):
"""Tests any type of regenerating."""
# Preps
wallet_name = "test_wallet_new"
wallet_hotkey = "test_hotkey_new"
wallet_path = (tmp_path / "test_wallets_new").resolve().as_posix()
# Call
w = Wallet(name=wallet_name, hotkey=wallet_hotkey, path=wallet_path)
with pytest.raises(KeyFileError):
_ = w.coldkey
with pytest.raises(KeyFileError):
_ = w.hotkey
with pytest.raises(KeyFileError):
_ = w.coldkeypub
with pytest.raises(KeyFileError):
_ = w.hotkeypub
w.create(coldkey_use_password=False)
ss58_coldkey = w.coldkey.ss58_address
ss58_coldkeypub = w.coldkeypub.ss58_address
ss58_hotkey = w.hotkey.ss58_address
ss58_hotkeypub = w.hotkeypub.ss58_address
w.regenerate_hotkeypub(ss58_address=ss58_hotkey, overwrite=True)
new_ss58_hotkeypub = w.hotkeypub.ss58_address
# Assert
assert ss58_coldkey == ss58_coldkeypub
assert ss58_hotkey == ss58_hotkeypub
assert ss58_hotkeypub == new_ss58_hotkeypub

Sorry, the diff of this file is too big to display