Skip to main content

No project description provided

Project description

Bittensor Wallet SDK

Install

There are a few ways to install Bittensor

  1. From source for usage:
$ git clone https://github.com/opentensor/btwallet.git
$ python3 -m pip install -e bittensor_wallet/
  1. From source for development needs:
$ 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
  1. From PyPI (currently unavailable):
$ python3 -m venv venv  # create env
$ source venv/bin/activate  # activate env
$ pip install bittensor-wallet  # install bittensor-wallet

To test your installation using python

from bittensor_wallet import Wallet

# creates wallet with name `default`
wallet = Wallet()
wallet.create()

If you want to pass arguments to the class other than the default, use the following:

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:

from bittensor_wallet.config import Config
config = Config()

Rust

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

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

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")) == Tru

# 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

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

# 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

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

# 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

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

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

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

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

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

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

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

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bittensor_wallet-2.0.0a2.tar.gz (62.7 kB view hashes)

Uploaded Source

Built Distributions

bittensor_wallet-2.0.0a2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.1 MB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64

bittensor_wallet-2.0.0a2-cp312-cp312-macosx_11_0_arm64.whl (736.8 kB view hashes)

Uploaded CPython 3.12 macOS 11.0+ ARM64

bittensor_wallet-2.0.0a2-cp312-cp312-macosx_10_12_x86_64.whl (777.5 kB view hashes)

Uploaded CPython 3.12 macOS 10.12+ x86-64

bittensor_wallet-2.0.0a2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.1 MB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

bittensor_wallet-2.0.0a2-cp311-cp311-macosx_11_0_arm64.whl (737.3 kB view hashes)

Uploaded CPython 3.11 macOS 11.0+ ARM64

bittensor_wallet-2.0.0a2-cp311-cp311-macosx_10_12_x86_64.whl (779.6 kB view hashes)

Uploaded CPython 3.11 macOS 10.12+ x86-64

bittensor_wallet-2.0.0a2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.1 MB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

bittensor_wallet-2.0.0a2-cp310-cp310-macosx_11_0_arm64.whl (737.2 kB view hashes)

Uploaded CPython 3.10 macOS 11.0+ ARM64

bittensor_wallet-2.0.0a2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.1 MB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

bittensor_wallet-2.0.0a2-cp39-cp39-macosx_11_0_arm64.whl (738.1 kB view hashes)

Uploaded CPython 3.9 macOS 11.0+ ARM64

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page