hippius 0.2.30__py3-none-any.whl → 0.2.32__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hippius
3
- Version: 0.2.30
3
+ Version: 0.2.32
4
4
  Summary: Python SDK and CLI for Hippius blockchain storage
5
5
  Home-page: https://github.com/thenervelab/hippius-sdk
6
6
  Author: Dubs
@@ -1,23 +1,24 @@
1
- hippius_sdk/__init__.py,sha256=0uGJ165jMUoucM0w6ftBO81B9hDfCEMRdH5mH65MD6o,1474
1
+ hippius_sdk/__init__.py,sha256=8FFxrpAn61D-ViCK1aikqZ6-5TLbGt1T4kTHygQ1nfA,1474
2
2
  hippius_sdk/cli.py,sha256=aqKOYSBSWt7UhcpFt7wf9yIPJ3bznpsJ6ehOnuZ4usI,18235
3
3
  hippius_sdk/cli_assets.py,sha256=V3MX63QTiex6mCp0VDXQJ7cagm5v1s4xtsu8c1O4G_k,371
4
4
  hippius_sdk/cli_handlers.py,sha256=TQNE9os87gRzRKLEO-SIwhFnBtEFMiaSESv-Bu7omfo,128909
5
5
  hippius_sdk/cli_parser.py,sha256=z7UvgWvvy04ey-R56qZiCqYc_9RaNq1rVDkQyXoK3JU,21100
6
6
  hippius_sdk/cli_rich.py,sha256=_jTBYMdHi2--fIVwoeNi-EtkdOb6Zy_O2TUiGvU3O7s,7324
7
- hippius_sdk/client.py,sha256=ft4gxn3NUvpiWm2R037BbsmJ9xOe8AiQpkrGQo4WUBw,22505
7
+ hippius_sdk/client.py,sha256=4Y2OdoXay2tBOsZVvXyxXccDkmtQ3R8YTUtlAMZBKfU,22545
8
8
  hippius_sdk/config.py,sha256=Hf_aUYzG9ylzqauA_ABUSSB5mBTYbp-VtB36VQt2XDw,21981
9
9
  hippius_sdk/db/README.md,sha256=okDeI1qgkaZqXSlJ8L0xIE4UpuxO-qEGPIbXUvSHQjU,2030
10
10
  hippius_sdk/db/env.db.template,sha256=_6hEC3IvkzCDOAzG1_yJUKRUfCTMciNaJUicZpMCat4,217
11
11
  hippius_sdk/db/migrations/20241201000001_create_key_storage_tables.sql,sha256=mi4-6OofgsmJq3PTG4ew8VNucoeb7iejyqd-bado7Mc,1613
12
+ hippius_sdk/db/migrations/20241202000001_switch_to_subaccount_encryption.sql,sha256=jBBeo2UYlEQIsyyQRPf0YsAykWpGfafN2E6dlDwAA_E,1399
12
13
  hippius_sdk/db/setup_database.sh,sha256=bDeIiTnMuX0AYCdefAfEI1CyXho6A6kLzufsDZFSXpE,3118
13
14
  hippius_sdk/db_utils.py,sha256=-x0rbN0as7Tn3PJPZBYCgreZe52FLH40ppA1TLxsg90,1851
14
15
  hippius_sdk/errors.py,sha256=LScJJmawVAx7aRzqqQguYSkf9iazSjEQEBNlD_GXZ6Y,1589
15
- hippius_sdk/ipfs.py,sha256=8OLkBkNV7zEKqrtokAwrvD842qXt8qgFMIc03h_sdN0,94610
16
+ hippius_sdk/ipfs.py,sha256=1kjWAMeGMAn8vpIrrpjAxTHvnCwruhFtWjQ18iGXSU8,95383
16
17
  hippius_sdk/ipfs_core.py,sha256=eOOgLoyP9mvwndnCjldnTc7z94ImYCXY3nm7JU3e_Mo,12676
17
- hippius_sdk/key_storage.py,sha256=oxfRRQXu8XVncUjhKJJ8rsc81JAkaj9MqZEwQa96idc,9474
18
- hippius_sdk/substrate.py,sha256=n4V2poNUHsXWpXq6va2f8mk5LwN3JgLClWQrYmI4hmw,49671
18
+ hippius_sdk/key_storage.py,sha256=SXFd6aGQw9MDLGX2vSBuAY7rdX-k5EvFm63z7_n-8yQ,8148
19
+ hippius_sdk/substrate.py,sha256=MFQcJARFw-Ej1WDSPGF8ryejXLmda5DdqcwPYS-KI10,49668
19
20
  hippius_sdk/utils.py,sha256=rJ611yvwKSyiBpYU3w-SuyQxoghMGU-ePuslrPv5H5g,7388
20
- hippius-0.2.30.dist-info/METADATA,sha256=Wt_z03c306Pf2pMXxXMljqhh6PKs1QzC4UwGBtEmMWs,30088
21
- hippius-0.2.30.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
22
- hippius-0.2.30.dist-info/entry_points.txt,sha256=bFAZjW3vndretf9-8s587jA2ebMVI7puhn_lVs8jPc8,149
23
- hippius-0.2.30.dist-info/RECORD,,
21
+ hippius-0.2.32.dist-info/METADATA,sha256=8nDrlRkci7_eTNeKFQKsn2VDsQVSuAnT6esx9NVYyg8,30088
22
+ hippius-0.2.32.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
23
+ hippius-0.2.32.dist-info/entry_points.txt,sha256=bFAZjW3vndretf9-8s587jA2ebMVI7puhn_lVs8jPc8,149
24
+ hippius-0.2.32.dist-info/RECORD,,
hippius_sdk/__init__.py CHANGED
@@ -26,7 +26,7 @@ from hippius_sdk.config import (
26
26
  from hippius_sdk.ipfs import IPFSClient, S3PublishResult, S3DownloadResult
27
27
  from hippius_sdk.utils import format_cid, format_size, hex_to_ipfs_cid
28
28
 
29
- __version__ = "0.2.30"
29
+ __version__ = "0.2.32"
30
30
  __all__ = [
31
31
  "HippiusClient",
32
32
  "IPFSClient",
hippius_sdk/client.py CHANGED
@@ -516,6 +516,7 @@ class HippiusClient:
516
516
  file_path: str,
517
517
  encrypt: bool,
518
518
  seed_phrase: str,
519
+ subaccount_id: str,
519
520
  store_node: str = "http://localhost:5001",
520
521
  pin_node: str = "https://store.hippius.network",
521
522
  substrate_url: str = "wss://rpc.hippius.network",
@@ -548,6 +549,7 @@ class HippiusClient:
548
549
  file_path,
549
550
  encrypt,
550
551
  seed_phrase,
552
+ subaccount_id,
551
553
  store_node,
552
554
  pin_node,
553
555
  substrate_url,
@@ -557,7 +559,7 @@ class HippiusClient:
557
559
  self,
558
560
  cid: str,
559
561
  output_path: str,
560
- seed_phrase: str,
562
+ subaccount_id: str,
561
563
  auto_decrypt: bool = True,
562
564
  download_node: str = "http://localhost:5001",
563
565
  ) -> S3DownloadResult:
@@ -574,7 +576,7 @@ class HippiusClient:
574
576
  Args:
575
577
  cid: Content Identifier (CID) of the file to download
576
578
  output_path: Path where the downloaded file will be saved
577
- seed_phrase: Seed phrase to use for retrieving decryption keys
579
+ subaccount_id: The subaccount id as api key
578
580
  auto_decrypt: Whether to attempt automatic decryption (default: True)
579
581
  download_node: IPFS node URL for download (default: local node)
580
582
 
@@ -587,5 +589,5 @@ class HippiusClient:
587
589
  ValueError: If decryption fails
588
590
  """
589
591
  return await self.ipfs_client.s3_download(
590
- cid, output_path, seed_phrase, auto_decrypt, download_node
592
+ cid, output_path, subaccount_id, auto_decrypt, download_node
591
593
  )
@@ -0,0 +1,34 @@
1
+ -- migrate:up
2
+
3
+ -- For security reasons, completely drop all existing tables and data
4
+ -- This removes any stored seed phrases from the database
5
+ DROP TABLE IF EXISTS encryption_keys CASCADE;
6
+ DROP TABLE IF EXISTS seed_phrases CASCADE;
7
+
8
+ -- Create new simplified schema using only subaccount_id
9
+ -- No seed phrases are stored in the database anymore
10
+ CREATE TABLE encryption_keys (
11
+ id SERIAL PRIMARY KEY,
12
+ subaccount_id VARCHAR(255) NOT NULL,
13
+ encryption_key_b64 TEXT NOT NULL,
14
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
15
+ );
16
+
17
+ -- Index for efficient lookups of latest encryption key per subaccount
18
+ CREATE INDEX idx_encryption_keys_subaccount_created
19
+ ON encryption_keys(subaccount_id, created_at DESC);
20
+
21
+ -- Comments for documentation
22
+ COMMENT ON TABLE encryption_keys IS 'Stores versioned encryption keys per subaccount ID (never deleted, always use most recent)';
23
+ COMMENT ON COLUMN encryption_keys.subaccount_id IS 'Subaccount identifier for key association';
24
+ COMMENT ON COLUMN encryption_keys.encryption_key_b64 IS 'Base64 encoded encryption key';
25
+
26
+ -- migrate:down
27
+
28
+ -- Drop new table
29
+ DROP INDEX IF EXISTS idx_encryption_keys_subaccount_created;
30
+ DROP TABLE IF EXISTS encryption_keys;
31
+
32
+ -- Note: We do NOT recreate the old seed_phrases table in the down migration
33
+ -- This is intentional for security - once we've removed seed phrases from the DB,
34
+ -- we don't want to accidentally restore them
hippius_sdk/ipfs.py CHANGED
@@ -21,8 +21,8 @@ from hippius_sdk.config import get_config_value, get_encryption_key
21
21
  from hippius_sdk.errors import HippiusIPFSError, HippiusSubstrateError
22
22
  from hippius_sdk.ipfs_core import AsyncIPFSClient
23
23
  from hippius_sdk.key_storage import (
24
- generate_and_store_key_for_seed,
25
- get_key_for_seed,
24
+ generate_and_store_key_for_subaccount,
25
+ get_key_for_subaccount,
26
26
  is_key_storage_enabled,
27
27
  )
28
28
  from hippius_sdk.substrate import FileInput, SubstrateClient
@@ -1648,6 +1648,7 @@ class IPFSClient:
1648
1648
  self,
1649
1649
  cid: str,
1650
1650
  cancel_from_blockchain: bool = True,
1651
+ unpin: bool = True,
1651
1652
  seed_phrase: Optional[str] = None,
1652
1653
  ) -> Dict[str, Any]:
1653
1654
  """
@@ -1657,6 +1658,7 @@ class IPFSClient:
1657
1658
  Args:
1658
1659
  cid: Content Identifier (CID) of the file/directory to delete
1659
1660
  cancel_from_blockchain: Whether to also cancel the storage request from the blockchain
1661
+ unpin: Whether to unpin the file from IPFS (default: True)
1660
1662
  seed_phrase: Optional seed phrase to use for blockchain interactions (uses config if None)
1661
1663
 
1662
1664
  Returns:
@@ -1709,21 +1711,26 @@ class IPFSClient:
1709
1711
  ):
1710
1712
  # Recursive delete, but don't cancel from blockchain (we'll do that for parent)
1711
1713
  await self.delete_file(
1712
- link_hash, cancel_from_blockchain=False
1714
+ link_hash, cancel_from_blockchain=False, unpin=unpin
1713
1715
  )
1714
1716
  else:
1715
1717
  # Regular file unpin
1716
- try:
1717
- await self.client.unpin(link_hash)
1718
- print(
1719
- f"Unpinned file: {link_name} (CID: {link_hash})"
1720
- )
1721
- except Exception as unpin_error:
1722
- # Just note the error but don't let it stop the whole process
1723
- # This is common with IPFS servers that may return 500 errors for
1724
- # unpinning content that was never explicitly pinned
1718
+ if unpin:
1719
+ try:
1720
+ await self.client.unpin(link_hash)
1721
+ print(
1722
+ f"Unpinned file: {link_name} (CID: {link_hash})"
1723
+ )
1724
+ except Exception as unpin_error:
1725
+ # Just note the error but don't let it stop the whole process
1726
+ # This is common with IPFS servers that may return 500 errors for
1727
+ # unpinning content that was never explicitly pinned
1728
+ print(
1729
+ f"Note: Could not unpin {link_name}: {str(unpin_error).split('For more information')[0]}"
1730
+ )
1731
+ else:
1725
1732
  print(
1726
- f"Note: Could not unpin {link_name}: {str(unpin_error).split('For more information')[0]}"
1733
+ f"Skipped unpinning file: {link_name} (CID: {link_hash})"
1727
1734
  )
1728
1735
  except Exception as e:
1729
1736
  print(
@@ -1737,27 +1744,32 @@ class IPFSClient:
1737
1744
  # Continue with regular file unpin
1738
1745
 
1739
1746
  # Now unpin the main file/directory
1740
- try:
1741
- print(f"Unpinning from IPFS: {cid}")
1742
- unpin_result = await self.client.unpin(cid)
1743
- result["unpin_result"] = unpin_result
1744
- result["success"] = True
1745
- print("Successfully unpinned from IPFS")
1746
- except Exception as e:
1747
- # Handle 500 errors from IPFS server gracefully - they often occur
1748
- # when the content wasn't explicitly pinned or was already unpinned
1749
- error_str = str(e)
1750
- if "500 Internal Server Error" in error_str:
1751
- print(
1752
- f"Note: IPFS server reported content may already be unpinned: {cid}"
1753
- )
1754
- result["unpin_result"] = {"Pins": [cid]} # Simulate successful unpin
1747
+ if unpin:
1748
+ try:
1749
+ print(f"Unpinning from IPFS: {cid}")
1750
+ unpin_result = await self.client.unpin(cid)
1751
+ result["unpin_result"] = unpin_result
1755
1752
  result["success"] = True
1756
- else:
1757
- print(
1758
- f"Warning: Failed to unpin from IPFS: {error_str.split('For more information')[0]}"
1759
- )
1760
- result["success"] = False
1753
+ print("Successfully unpinned from IPFS")
1754
+ except Exception as e:
1755
+ # Handle 500 errors from IPFS server gracefully - they often occur
1756
+ # when the content wasn't explicitly pinned or was already unpinned
1757
+ error_str = str(e)
1758
+ if "500 Internal Server Error" in error_str:
1759
+ print(
1760
+ f"Note: IPFS server reported content may already be unpinned: {cid}"
1761
+ )
1762
+ result["unpin_result"] = {"Pins": [cid]} # Simulate successful unpin
1763
+ result["success"] = True
1764
+ else:
1765
+ print(
1766
+ f"Warning: Failed to unpin from IPFS: {error_str.split('For more information')[0]}"
1767
+ )
1768
+ result["success"] = False
1769
+ else:
1770
+ print(f"Skipped unpinning from IPFS: {cid}")
1771
+ result["unpin_result"] = {"skipped": True}
1772
+ result["success"] = True
1761
1773
 
1762
1774
  # Then, if requested, cancel from blockchain
1763
1775
  if cancel_from_blockchain:
@@ -1939,6 +1951,7 @@ class IPFSClient:
1939
1951
  file_path: str,
1940
1952
  encrypt: bool,
1941
1953
  seed_phrase: str,
1954
+ subaccount_id: str,
1942
1955
  store_node: str = "http://localhost:5001",
1943
1956
  pin_node: str = "https://store.hippius.network",
1944
1957
  substrate_url: str = "wss://rpc.hippius.network",
@@ -1994,17 +2007,19 @@ class IPFSClient:
1994
2007
 
1995
2008
  if key_storage_available:
1996
2009
  # Try to get existing key for this seed phrase
1997
- existing_key_b64 = await get_key_for_seed(seed_phrase)
2010
+ existing_key_b64 = await get_key_for_subaccount(subaccount_id)
1998
2011
 
1999
2012
  if existing_key_b64:
2000
2013
  # Use existing key
2001
- logger.debug("Using existing encryption key for seed phrase")
2014
+ logger.debug("Using existing encryption key for subaccount")
2002
2015
  encryption_key_bytes = base64.b64decode(existing_key_b64)
2003
2016
  encryption_key_used = existing_key_b64
2004
2017
  else:
2005
- # Generate and store new key for this seed phrase
2006
- logger.info("Generating new encryption key for seed phrase")
2007
- new_key_b64 = await generate_and_store_key_for_seed(seed_phrase)
2018
+ # Generate and store new key for this subaccount
2019
+ logger.info("Generating new encryption key for subaccount")
2020
+ new_key_b64 = await generate_and_store_key_for_subaccount(
2021
+ subaccount_id
2022
+ )
2008
2023
  encryption_key_bytes = base64.b64decode(new_key_b64)
2009
2024
  encryption_key_used = new_key_b64
2010
2025
 
@@ -2120,7 +2135,7 @@ class IPFSClient:
2120
2135
  self,
2121
2136
  cid: str,
2122
2137
  output_path: str,
2123
- seed_phrase: str,
2138
+ subaccount_id: str,
2124
2139
  auto_decrypt: bool = True,
2125
2140
  download_node: str = "http://localhost:5001",
2126
2141
  ) -> S3DownloadResult:
@@ -2137,7 +2152,7 @@ class IPFSClient:
2137
2152
  Args:
2138
2153
  cid: Content Identifier (CID) of the file to download
2139
2154
  output_path: Path where the downloaded file will be saved
2140
- seed_phrase: Seed phrase to use for retrieving decryption keys
2155
+ subaccount_id: The subaccount id as api key
2141
2156
  auto_decrypt: Whether to attempt automatic decryption (default: True)
2142
2157
  download_node: IPFS node URL for download (default: local node)
2143
2158
 
@@ -2218,11 +2233,11 @@ class IPFSClient:
2218
2233
  if key_storage_available:
2219
2234
  # Try to get the encryption key for this seed phrase
2220
2235
  try:
2221
- existing_key_b64 = await get_key_for_seed(seed_phrase)
2236
+ existing_key_b64 = await get_key_for_subaccount(subaccount_id)
2222
2237
 
2223
2238
  if existing_key_b64:
2224
2239
  logger.debug(
2225
- "Found encryption key for seed phrase, attempting decryption"
2240
+ "Found encryption key for subaccount, attempting decryption"
2226
2241
  )
2227
2242
  decryption_attempted = True
2228
2243
  encryption_key_used = existing_key_b64
@@ -1,15 +1,12 @@
1
1
  """
2
- Key storage module for managing encryption keys per seed phrase.
2
+ Key storage module for managing encryption keys per subaccount ID.
3
3
 
4
4
  This module provides PostgreSQL-backed storage for:
5
- 1. Base64 encoded seed phrases
6
- 2. Encryption keys associated with each seed phrase (versioned, never deleted)
5
+ 1. Encryption keys associated with each subaccount ID (versioned, never deleted)
7
6
  """
8
7
 
9
8
  import base64
10
9
  import hashlib
11
- import os
12
- from datetime import datetime
13
10
  from typing import Optional
14
11
 
15
12
  from hippius_sdk.config import get_config_value
@@ -30,7 +27,7 @@ class KeyStorageError(Exception):
30
27
 
31
28
 
32
29
  class KeyStorage:
33
- """PostgreSQL-backed key storage for seed phrases and encryption keys."""
30
+ """PostgreSQL-backed key storage for subaccount encryption keys."""
34
31
 
35
32
  def __init__(self, database_url: Optional[str] = None):
36
33
  """
@@ -62,34 +59,23 @@ class KeyStorage:
62
59
 
63
60
  async def _ensure_tables_exist(self):
64
61
  """Create tables if they don't exist."""
65
- create_seed_phrases_table = """
66
- CREATE TABLE IF NOT EXISTS seed_phrases (
67
- id SERIAL PRIMARY KEY,
68
- seed_hash VARCHAR(64) UNIQUE NOT NULL,
69
- seed_phrase_b64 TEXT NOT NULL,
70
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
71
- );
72
- """
73
-
74
62
  create_encryption_keys_table = """
75
63
  CREATE TABLE IF NOT EXISTS encryption_keys (
76
64
  id SERIAL PRIMARY KEY,
77
- seed_hash VARCHAR(64) NOT NULL,
65
+ subaccount_id VARCHAR(255) NOT NULL,
78
66
  encryption_key_b64 TEXT NOT NULL,
79
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
80
- FOREIGN KEY (seed_hash) REFERENCES seed_phrases(seed_hash)
67
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
81
68
  );
82
69
  """
83
70
 
84
71
  create_index = """
85
- CREATE INDEX IF NOT EXISTS idx_encryption_keys_seed_hash_created
86
- ON encryption_keys(seed_hash, created_at DESC);
72
+ CREATE INDEX IF NOT EXISTS idx_encryption_keys_subaccount_created
73
+ ON encryption_keys(subaccount_id, created_at DESC);
87
74
  """
88
75
 
89
76
  try:
90
77
  conn = await self._get_connection()
91
78
  try:
92
- await conn.execute(create_seed_phrases_table)
93
79
  await conn.execute(create_encryption_keys_table)
94
80
  await conn.execute(create_index)
95
81
  finally:
@@ -97,59 +83,37 @@ class KeyStorage:
97
83
  except Exception as e:
98
84
  raise KeyStorageError(f"Failed to create tables: {e}")
99
85
 
100
- def _hash_seed_phrase(self, seed_phrase: str) -> str:
101
- """Create a SHA-256 hash of the seed phrase for indexing."""
102
- return hashlib.sha256(seed_phrase.encode("utf-8")).hexdigest()
103
-
104
- async def _ensure_seed_phrase_exists(self, seed_phrase: str) -> str:
105
- """Ensure seed phrase exists in database and return its hash."""
106
- seed_hash = self._hash_seed_phrase(seed_phrase)
107
- seed_phrase_b64 = base64.b64encode(seed_phrase.encode("utf-8")).decode("utf-8")
108
-
109
- try:
110
- conn = await self._get_connection()
111
- try:
112
- # Try to insert, ignore if already exists
113
- await conn.execute(
114
- """
115
- INSERT INTO seed_phrases (seed_hash, seed_phrase_b64)
116
- VALUES ($1, $2)
117
- ON CONFLICT (seed_hash) DO NOTHING
118
- """,
119
- seed_hash,
120
- seed_phrase_b64,
121
- )
122
- finally:
123
- await conn.close()
124
- return seed_hash
125
- except Exception as e:
126
- raise KeyStorageError(f"Failed to store seed phrase: {e}")
86
+ def _hash_subaccount_id(self, subaccount_id: str) -> str:
87
+ """Create a SHA-256 hash of the subaccount ID for indexing."""
88
+ return hashlib.sha256(subaccount_id.encode("utf-8")).hexdigest()
127
89
 
128
- async def set_key_for_seed(self, seed_phrase: str, encryption_key_b64: str) -> None:
90
+ async def set_key_for_subaccount(
91
+ self, subaccount_id: str, encryption_key_b64: str
92
+ ) -> None:
129
93
  """
130
- Store a new encryption key for a seed phrase.
94
+ Store a new encryption key for a subaccount.
131
95
 
132
96
  Creates a new row (doesn't update existing ones) to maintain key history.
133
97
 
134
98
  Args:
135
- seed_phrase: The seed phrase
99
+ subaccount_id: The subaccount identifier
136
100
  encryption_key_b64: Base64-encoded encryption key
137
101
 
138
102
  Raises:
139
103
  KeyStorageError: If storage fails
140
104
  """
141
105
  await self._ensure_tables_exist()
142
- seed_hash = await self._ensure_seed_phrase_exists(seed_phrase)
106
+ subaccount_hash = self._hash_subaccount_id(subaccount_id)
143
107
 
144
108
  try:
145
109
  conn = await self._get_connection()
146
110
  try:
147
111
  await conn.execute(
148
112
  """
149
- INSERT INTO encryption_keys (seed_hash, encryption_key_b64)
113
+ INSERT INTO encryption_keys (subaccount_id, encryption_key_b64)
150
114
  VALUES ($1, $2)
151
115
  """,
152
- seed_hash,
116
+ subaccount_hash,
153
117
  encryption_key_b64,
154
118
  )
155
119
  finally:
@@ -157,12 +121,12 @@ class KeyStorage:
157
121
  except Exception as e:
158
122
  raise KeyStorageError(f"Failed to store encryption key: {e}")
159
123
 
160
- async def get_key_for_seed(self, seed_phrase: str) -> Optional[str]:
124
+ async def get_key_for_subaccount(self, subaccount_id: str) -> Optional[str]:
161
125
  """
162
- Get the most recent encryption key for a seed phrase.
126
+ Get the most recent encryption key for a subaccount.
163
127
 
164
128
  Args:
165
- seed_phrase: The seed phrase
129
+ subaccount_id: The subaccount identifier
166
130
 
167
131
  Returns:
168
132
  Base64-encoded encryption key or None if not found
@@ -171,7 +135,7 @@ class KeyStorage:
171
135
  KeyStorageError: If database operation fails
172
136
  """
173
137
  await self._ensure_tables_exist()
174
- seed_hash = self._hash_seed_phrase(seed_phrase)
138
+ subaccount_hash = self._hash_subaccount_id(subaccount_id)
175
139
 
176
140
  try:
177
141
  conn = await self._get_connection()
@@ -180,11 +144,11 @@ class KeyStorage:
180
144
  """
181
145
  SELECT encryption_key_b64
182
146
  FROM encryption_keys
183
- WHERE seed_hash = $1
147
+ WHERE subaccount_id = $1
184
148
  ORDER BY created_at DESC
185
149
  LIMIT 1
186
150
  """,
187
- seed_hash,
151
+ subaccount_hash,
188
152
  )
189
153
 
190
154
  return result["encryption_key_b64"] if result else None
@@ -193,12 +157,12 @@ class KeyStorage:
193
157
  except Exception as e:
194
158
  raise KeyStorageError(f"Failed to retrieve encryption key: {e}")
195
159
 
196
- async def generate_and_store_key_for_seed(self, seed_phrase: str) -> str:
160
+ async def generate_and_store_key_for_subaccount(self, subaccount_id: str) -> str:
197
161
  """
198
- Generate a new encryption key and store it for the seed phrase.
162
+ Generate a new encryption key and store it for the subaccount.
199
163
 
200
164
  Args:
201
- seed_phrase: The seed phrase
165
+ subaccount_id: The subaccount identifier
202
166
 
203
167
  Returns:
204
168
  Base64-encoded encryption key that was generated and stored
@@ -206,17 +170,14 @@ class KeyStorage:
206
170
  Raises:
207
171
  KeyStorageError: If generation or storage fails
208
172
  """
209
- # Generate a new encryption key
210
173
  try:
211
174
  import nacl.secret
212
175
  import nacl.utils
213
176
 
214
- # Generate a random key
215
177
  key = nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE)
216
178
  key_b64 = base64.b64encode(key).decode("utf-8")
217
179
 
218
- # Store it
219
- await self.set_key_for_seed(seed_phrase, key_b64)
180
+ await self.set_key_for_subaccount(subaccount_id, key_b64)
220
181
 
221
182
  return key_b64
222
183
  except ImportError:
@@ -261,38 +222,42 @@ def get_default_storage() -> KeyStorage:
261
222
  return _default_storage
262
223
 
263
224
 
264
- async def get_key_for_seed(seed_phrase: str) -> Optional[str]:
225
+ async def get_key_for_subaccount(subaccount_id: str) -> Optional[str]:
265
226
  """
266
- Get the most recent encryption key for a seed phrase.
227
+ Get the most recent encryption key for a subaccount.
267
228
 
268
229
  Args:
269
- seed_phrase: The seed phrase
230
+ subaccount_id: The subaccount identifier
270
231
 
271
232
  Returns:
272
233
  Base64-encoded encryption key or None if not found
273
234
  """
274
- return await get_default_storage().get_key_for_seed(seed_phrase)
235
+ return await get_default_storage().get_key_for_subaccount(subaccount_id)
275
236
 
276
237
 
277
- async def set_key_for_seed(seed_phrase: str, encryption_key_b64: str) -> None:
238
+ async def set_key_for_subaccount(subaccount_id: str, encryption_key_b64: str) -> None:
278
239
  """
279
- Store a new encryption key for a seed phrase.
240
+ Store a new encryption key for a subaccount.
280
241
 
281
242
  Args:
282
- seed_phrase: The seed phrase
243
+ subaccount_id: The subaccount identifier
283
244
  encryption_key_b64: Base64-encoded encryption key
284
245
  """
285
- return await get_default_storage().set_key_for_seed(seed_phrase, encryption_key_b64)
246
+ return await get_default_storage().set_key_for_subaccount(
247
+ subaccount_id, encryption_key_b64
248
+ )
286
249
 
287
250
 
288
- async def generate_and_store_key_for_seed(seed_phrase: str) -> str:
251
+ async def generate_and_store_key_for_subaccount(subaccount_id: str) -> str:
289
252
  """
290
- Generate a new encryption key and store it for the seed phrase.
253
+ Generate a new encryption key and store it for the subaccount.
291
254
 
292
255
  Args:
293
- seed_phrase: The seed phrase
256
+ subaccount_id: The subaccount identifier
294
257
 
295
258
  Returns:
296
259
  Base64-encoded encryption key that was generated and stored
297
260
  """
298
- return await get_default_storage().generate_and_store_key_for_seed(seed_phrase)
261
+ return await get_default_storage().generate_and_store_key_for_subaccount(
262
+ subaccount_id
263
+ )
hippius_sdk/substrate.py CHANGED
@@ -1270,7 +1270,6 @@ class SubstrateClient:
1270
1270
  return result.value
1271
1271
  return None
1272
1272
 
1273
-
1274
1273
  def is_main_account(self, account_id: str, seed_phrase: str) -> bool:
1275
1274
  sub_account = self.query_sub_account(account_id, seed_phrase=seed_phrase)
1276
1275
  return sub_account is None
@@ -1288,8 +1287,6 @@ class SubstrateClient:
1288
1287
  # Return the u128 value (converted to int for Python compatibility)
1289
1288
  return int(result.value) if result and result.value is not None else 0
1290
1289
 
1291
-
1292
-
1293
1290
  def get_account_roles(self, account_id: str, seed_phrase) -> int:
1294
1291
  if not self._substrate:
1295
1292
  self.connect(seed_phrase)