hive-nectar 0.2.9__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.
- hive_nectar-0.2.9.dist-info/METADATA +194 -0
- hive_nectar-0.2.9.dist-info/RECORD +87 -0
- hive_nectar-0.2.9.dist-info/WHEEL +4 -0
- hive_nectar-0.2.9.dist-info/entry_points.txt +2 -0
- hive_nectar-0.2.9.dist-info/licenses/LICENSE.txt +23 -0
- nectar/__init__.py +37 -0
- nectar/account.py +5076 -0
- nectar/amount.py +553 -0
- nectar/asciichart.py +303 -0
- nectar/asset.py +122 -0
- nectar/block.py +574 -0
- nectar/blockchain.py +1242 -0
- nectar/blockchaininstance.py +2590 -0
- nectar/blockchainobject.py +263 -0
- nectar/cli.py +5937 -0
- nectar/comment.py +1552 -0
- nectar/community.py +854 -0
- nectar/constants.py +95 -0
- nectar/discussions.py +1437 -0
- nectar/exceptions.py +152 -0
- nectar/haf.py +381 -0
- nectar/hive.py +630 -0
- nectar/imageuploader.py +114 -0
- nectar/instance.py +113 -0
- nectar/market.py +876 -0
- nectar/memo.py +542 -0
- nectar/message.py +379 -0
- nectar/nodelist.py +309 -0
- nectar/price.py +603 -0
- nectar/profile.py +74 -0
- nectar/py.typed +0 -0
- nectar/rc.py +333 -0
- nectar/snapshot.py +1024 -0
- nectar/storage.py +62 -0
- nectar/transactionbuilder.py +659 -0
- nectar/utils.py +630 -0
- nectar/version.py +3 -0
- nectar/vote.py +722 -0
- nectar/wallet.py +472 -0
- nectar/witness.py +728 -0
- nectarapi/__init__.py +12 -0
- nectarapi/exceptions.py +126 -0
- nectarapi/graphenerpc.py +596 -0
- nectarapi/node.py +194 -0
- nectarapi/noderpc.py +79 -0
- nectarapi/openapi.py +107 -0
- nectarapi/py.typed +0 -0
- nectarapi/rpcutils.py +98 -0
- nectarapi/version.py +3 -0
- nectarbase/__init__.py +15 -0
- nectarbase/ledgertransactions.py +106 -0
- nectarbase/memo.py +242 -0
- nectarbase/objects.py +521 -0
- nectarbase/objecttypes.py +21 -0
- nectarbase/operationids.py +102 -0
- nectarbase/operations.py +1357 -0
- nectarbase/py.typed +0 -0
- nectarbase/signedtransactions.py +89 -0
- nectarbase/transactions.py +11 -0
- nectarbase/version.py +3 -0
- nectargraphenebase/__init__.py +27 -0
- nectargraphenebase/account.py +1121 -0
- nectargraphenebase/aes.py +49 -0
- nectargraphenebase/base58.py +197 -0
- nectargraphenebase/bip32.py +575 -0
- nectargraphenebase/bip38.py +110 -0
- nectargraphenebase/chains.py +15 -0
- nectargraphenebase/dictionary.py +2 -0
- nectargraphenebase/ecdsasig.py +309 -0
- nectargraphenebase/objects.py +130 -0
- nectargraphenebase/objecttypes.py +8 -0
- nectargraphenebase/operationids.py +5 -0
- nectargraphenebase/operations.py +25 -0
- nectargraphenebase/prefix.py +13 -0
- nectargraphenebase/py.typed +0 -0
- nectargraphenebase/signedtransactions.py +221 -0
- nectargraphenebase/types.py +557 -0
- nectargraphenebase/unsignedtransactions.py +288 -0
- nectargraphenebase/version.py +3 -0
- nectarstorage/__init__.py +57 -0
- nectarstorage/base.py +317 -0
- nectarstorage/exceptions.py +15 -0
- nectarstorage/interfaces.py +244 -0
- nectarstorage/masterpassword.py +237 -0
- nectarstorage/py.typed +0 -0
- nectarstorage/ram.py +27 -0
- nectarstorage/sqlite.py +343 -0
nectar/wallet.py
ADDED
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any, Dict, Generator, List, Optional, Union
|
|
5
|
+
|
|
6
|
+
from nectar.instance import shared_blockchain_instance
|
|
7
|
+
from nectargraphenebase.account import PrivateKey
|
|
8
|
+
from nectarstorage.exceptions import KeyAlreadyInStoreException
|
|
9
|
+
|
|
10
|
+
from .account import Account
|
|
11
|
+
from .exceptions import (
|
|
12
|
+
AccountDoesNotExistsException,
|
|
13
|
+
InvalidWifError,
|
|
14
|
+
MissingKeyError,
|
|
15
|
+
OfflineHasNoRPCException,
|
|
16
|
+
WalletExists,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
log = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Wallet:
|
|
23
|
+
"""The wallet is meant to maintain access to private keys for
|
|
24
|
+
your accounts. It either uses manually provided private keys
|
|
25
|
+
or uses a SQLite database managed by storage.py.
|
|
26
|
+
|
|
27
|
+
:param Rpc rpc: RPC connection to a Hive node
|
|
28
|
+
:param keys: Predefine the wif keys to shortcut the
|
|
29
|
+
wallet database
|
|
30
|
+
:type keys: array, dict, str
|
|
31
|
+
|
|
32
|
+
Three wallet operation modes are possible:
|
|
33
|
+
|
|
34
|
+
* **Wallet Database**: Here, nectar loads the keys from the
|
|
35
|
+
locally stored wallet SQLite database (see ``storage.py``).
|
|
36
|
+
To use this mode, simply call :class:`nectar.hive.Hive` without the
|
|
37
|
+
``keys`` parameter
|
|
38
|
+
* **Providing Keys**: Here, you can provide the keys for
|
|
39
|
+
your accounts manually. All you need to do is add the wif
|
|
40
|
+
keys for the accounts you want to use as a simple array
|
|
41
|
+
using the ``keys`` parameter to :class:`nectar.hive.Hive`.
|
|
42
|
+
* **Force keys**: This more is for advanced users and
|
|
43
|
+
requires that you know what you are doing. Here, the
|
|
44
|
+
``keys`` parameter is a dictionary that overwrite the
|
|
45
|
+
``active``, ``owner``, ``posting`` or ``memo`` keys for
|
|
46
|
+
any account. This mode is only used for *foreign*
|
|
47
|
+
signatures!
|
|
48
|
+
|
|
49
|
+
A new wallet can be created by using:
|
|
50
|
+
|
|
51
|
+
.. code-block:: python
|
|
52
|
+
|
|
53
|
+
from nectar import Hive
|
|
54
|
+
hive = Hive()
|
|
55
|
+
hive.wallet.wipe(True)
|
|
56
|
+
hive.wallet.create("supersecret-passphrase")
|
|
57
|
+
|
|
58
|
+
This will raise :class:`nectar.exceptions.WalletExists` if you already have a wallet installed.
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
The wallet can be unlocked for signing using
|
|
62
|
+
|
|
63
|
+
.. code-block:: python
|
|
64
|
+
|
|
65
|
+
from nectar import Hive
|
|
66
|
+
hive = Hive()
|
|
67
|
+
hive.wallet.unlock("supersecret-passphrase")
|
|
68
|
+
|
|
69
|
+
A private key can be added by using the
|
|
70
|
+
:func:`addPrivateKey` method that is available
|
|
71
|
+
**after** unlocking the wallet with the correct passphrase:
|
|
72
|
+
|
|
73
|
+
.. code-block:: python
|
|
74
|
+
|
|
75
|
+
from nectar import Hive
|
|
76
|
+
hive = Hive()
|
|
77
|
+
hive.wallet.unlock("supersecret-passphrase")
|
|
78
|
+
hive.wallet.addPrivateKey("5xxxxxxxxxxxxxxxxxxxx")
|
|
79
|
+
|
|
80
|
+
.. note:: The private key has to be either in hexadecimal or in wallet
|
|
81
|
+
import format (wif) (starting with a ``5``).
|
|
82
|
+
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
def __init__(
|
|
86
|
+
self, blockchain_instance: Optional[Any] = None, *args: Any, **kwargs: Any
|
|
87
|
+
) -> None:
|
|
88
|
+
"""
|
|
89
|
+
Initialize the Wallet, binding it to a blockchain instance and setting up the underlying key store.
|
|
90
|
+
|
|
91
|
+
If a blockchain_instance is provided, it is used; otherwise the shared blockchain instance is used. Accepts legacy "wif" argument (aliased to "keys"). If non-empty "keys" are supplied, an in-memory plain key store is created and populated; otherwise a SQLite-encrypted key store is instantiated (can be overridden via the `key_store` kwarg).
|
|
92
|
+
|
|
93
|
+
Parameters:
|
|
94
|
+
blockchain_instance (optional): Explicit blockchain/RPC wrapper to use; if omitted the module's shared blockchain instance is used.
|
|
95
|
+
|
|
96
|
+
Side effects:
|
|
97
|
+
- Creates and assigns self.store to either an in-memory or persistent key store.
|
|
98
|
+
- Calls setKeys when an in-memory store is selected.
|
|
99
|
+
"""
|
|
100
|
+
self.blockchain = blockchain_instance or shared_blockchain_instance()
|
|
101
|
+
|
|
102
|
+
# Compatibility after name change from wif->keys
|
|
103
|
+
if "wif" in kwargs and "keys" not in kwargs:
|
|
104
|
+
kwargs["keys"] = kwargs["wif"]
|
|
105
|
+
|
|
106
|
+
self.store: Any
|
|
107
|
+
if "keys" in kwargs and len(kwargs["keys"]) > 0:
|
|
108
|
+
from nectarstorage import InRamPlainKeyStore
|
|
109
|
+
|
|
110
|
+
self.store = InRamPlainKeyStore()
|
|
111
|
+
self.setKeys(kwargs["keys"])
|
|
112
|
+
else:
|
|
113
|
+
""" If no keys are provided manually we load the SQLite
|
|
114
|
+
keyStorage
|
|
115
|
+
"""
|
|
116
|
+
from nectarstorage import SqliteEncryptedKeyStore
|
|
117
|
+
|
|
118
|
+
self.store = kwargs.get(
|
|
119
|
+
"key_store",
|
|
120
|
+
SqliteEncryptedKeyStore(config=self.blockchain.config, **kwargs),
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def prefix(self) -> str:
|
|
125
|
+
if self.blockchain.is_connected():
|
|
126
|
+
prefix = self.blockchain.prefix
|
|
127
|
+
else:
|
|
128
|
+
# If not connected, load prefix from config
|
|
129
|
+
prefix = self.blockchain.config["prefix"]
|
|
130
|
+
return prefix or "STM" # default prefix is STM
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def rpc(self) -> Any:
|
|
134
|
+
if not self.blockchain.is_connected():
|
|
135
|
+
raise OfflineHasNoRPCException("No RPC available in offline mode!")
|
|
136
|
+
return self.blockchain.rpc
|
|
137
|
+
|
|
138
|
+
def setKeys(self, loadkeys: Union[Dict[str, Any], List[Any], set, str]) -> None:
|
|
139
|
+
"""This method is strictly only for in memory keys that are
|
|
140
|
+
passed to Wallet with the ``keys`` argument
|
|
141
|
+
"""
|
|
142
|
+
log.debug("Force setting of private keys. Not using the wallet database!")
|
|
143
|
+
if isinstance(loadkeys, dict):
|
|
144
|
+
loadkeys = list(loadkeys.values())
|
|
145
|
+
elif not isinstance(loadkeys, (list, set)):
|
|
146
|
+
loadkeys = [loadkeys]
|
|
147
|
+
for wif in loadkeys:
|
|
148
|
+
pub = self.publickey_from_wif(wif)
|
|
149
|
+
self.store.add(str(wif), pub)
|
|
150
|
+
|
|
151
|
+
def is_encrypted(self) -> bool:
|
|
152
|
+
"""Is the key store encrypted?"""
|
|
153
|
+
return self.store.is_encrypted()
|
|
154
|
+
|
|
155
|
+
def unlock(self, pwd: str) -> Optional[bool]:
|
|
156
|
+
"""Unlock the wallet database"""
|
|
157
|
+
unlock_ok = None
|
|
158
|
+
if self.store.is_encrypted():
|
|
159
|
+
unlock_ok = self.store.unlock(pwd)
|
|
160
|
+
return unlock_ok
|
|
161
|
+
|
|
162
|
+
def lock(self) -> bool:
|
|
163
|
+
"""Lock the wallet database"""
|
|
164
|
+
lock_ok = False
|
|
165
|
+
if self.store.is_encrypted():
|
|
166
|
+
lock_ok = self.store.lock()
|
|
167
|
+
return lock_ok
|
|
168
|
+
|
|
169
|
+
def unlocked(self) -> bool:
|
|
170
|
+
"""Is the wallet database unlocked?"""
|
|
171
|
+
unlocked = True
|
|
172
|
+
if self.store.is_encrypted():
|
|
173
|
+
unlocked = not self.store.locked()
|
|
174
|
+
return unlocked
|
|
175
|
+
|
|
176
|
+
def locked(self) -> bool:
|
|
177
|
+
"""Is the wallet database locked?"""
|
|
178
|
+
if self.store.is_encrypted():
|
|
179
|
+
return self.store.locked()
|
|
180
|
+
else:
|
|
181
|
+
return False
|
|
182
|
+
|
|
183
|
+
def changePassphrase(self, new_pwd: str) -> None:
|
|
184
|
+
"""Change the passphrase for the wallet database"""
|
|
185
|
+
self.store.change_password(new_pwd)
|
|
186
|
+
|
|
187
|
+
def created(self) -> bool:
|
|
188
|
+
"""Do we have a wallet database already?"""
|
|
189
|
+
if len(self.store.getPublicKeys()):
|
|
190
|
+
# Already keys installed
|
|
191
|
+
return True
|
|
192
|
+
else:
|
|
193
|
+
return False
|
|
194
|
+
|
|
195
|
+
def create(self, pwd: str) -> None:
|
|
196
|
+
"""Alias for :func:`newWallet`
|
|
197
|
+
|
|
198
|
+
:param str pwd: Passphrase for the created wallet
|
|
199
|
+
"""
|
|
200
|
+
self.newWallet(pwd)
|
|
201
|
+
|
|
202
|
+
def newWallet(self, pwd: str) -> None:
|
|
203
|
+
"""Create a new wallet database
|
|
204
|
+
|
|
205
|
+
:param str pwd: Passphrase for the created wallet
|
|
206
|
+
"""
|
|
207
|
+
if self.created():
|
|
208
|
+
raise WalletExists("You already have created a wallet!")
|
|
209
|
+
self.store.unlock(pwd)
|
|
210
|
+
|
|
211
|
+
def privatekey(self, key: str) -> PrivateKey:
|
|
212
|
+
return PrivateKey(key, prefix=self.prefix)
|
|
213
|
+
|
|
214
|
+
def publickey_from_wif(self, wif: str) -> str:
|
|
215
|
+
return str(self.privatekey(str(wif)).pubkey)
|
|
216
|
+
|
|
217
|
+
def addPrivateKey(self, wif: str) -> None:
|
|
218
|
+
"""Add a private key to the wallet database
|
|
219
|
+
|
|
220
|
+
:param str wif: Private key
|
|
221
|
+
"""
|
|
222
|
+
try:
|
|
223
|
+
pub = self.publickey_from_wif(wif)
|
|
224
|
+
except Exception:
|
|
225
|
+
raise InvalidWifError("Invalid Key format!")
|
|
226
|
+
if str(pub) in self.store:
|
|
227
|
+
raise KeyAlreadyInStoreException("Key already in the store")
|
|
228
|
+
self.store.add(str(wif), str(pub))
|
|
229
|
+
|
|
230
|
+
def getPrivateKeyForPublicKey(self, pub: str) -> Optional[str]:
|
|
231
|
+
"""Obtain the private key for a given public key
|
|
232
|
+
|
|
233
|
+
:param str pub: Public Key
|
|
234
|
+
"""
|
|
235
|
+
if str(pub) not in self.store:
|
|
236
|
+
raise MissingKeyError
|
|
237
|
+
return self.store.getPrivateKeyForPublicKey(str(pub))
|
|
238
|
+
|
|
239
|
+
def removePrivateKeyFromPublicKey(self, pub: str) -> None:
|
|
240
|
+
"""Remove a key from the wallet database
|
|
241
|
+
|
|
242
|
+
:param str pub: Public key
|
|
243
|
+
"""
|
|
244
|
+
self.store.delete(str(pub))
|
|
245
|
+
|
|
246
|
+
def removeAccount(self, account: str) -> None:
|
|
247
|
+
"""Remove all keys associated with a given account
|
|
248
|
+
|
|
249
|
+
:param str account: name of account to be removed
|
|
250
|
+
"""
|
|
251
|
+
accounts = self.getAccounts()
|
|
252
|
+
for a in accounts:
|
|
253
|
+
if a["name"] == account:
|
|
254
|
+
self.store.delete(a["pubkey"])
|
|
255
|
+
|
|
256
|
+
def getKeyForAccount(self, name: str, key_type: str) -> Optional[str]:
|
|
257
|
+
"""Obtain `key_type` Private Key for an account from the wallet database
|
|
258
|
+
|
|
259
|
+
:param str name: Account name
|
|
260
|
+
:param str key_type: key type, has to be one of "owner", "active",
|
|
261
|
+
"posting" or "memo"
|
|
262
|
+
"""
|
|
263
|
+
if key_type not in ["owner", "active", "posting", "memo"]:
|
|
264
|
+
raise AssertionError("Wrong key type")
|
|
265
|
+
|
|
266
|
+
account = self.rpc.find_accounts({"accounts": [name]})["accounts"]
|
|
267
|
+
if not account:
|
|
268
|
+
return
|
|
269
|
+
if len(account) == 0:
|
|
270
|
+
return
|
|
271
|
+
if key_type == "memo":
|
|
272
|
+
key = self.getPrivateKeyForPublicKey(account[0]["memo_key"])
|
|
273
|
+
if key:
|
|
274
|
+
return key
|
|
275
|
+
else:
|
|
276
|
+
key = None
|
|
277
|
+
for authority in account[0][key_type]["key_auths"]:
|
|
278
|
+
try:
|
|
279
|
+
key = self.getPrivateKeyForPublicKey(authority[0])
|
|
280
|
+
if key:
|
|
281
|
+
return key
|
|
282
|
+
except MissingKeyError:
|
|
283
|
+
key = None
|
|
284
|
+
if key is None:
|
|
285
|
+
raise MissingKeyError("No private key for {} found".format(name))
|
|
286
|
+
return
|
|
287
|
+
|
|
288
|
+
def getKeysForAccount(self, name: str, key_type: str) -> Optional[List[str]]:
|
|
289
|
+
"""Obtain a List of `key_type` Private Keys for an account from the wallet database
|
|
290
|
+
|
|
291
|
+
:param str name: Account name
|
|
292
|
+
:param str key_type: key type, has to be one of "owner", "active",
|
|
293
|
+
"posting" or "memo"
|
|
294
|
+
"""
|
|
295
|
+
if key_type not in ["owner", "active", "posting", "memo"]:
|
|
296
|
+
raise AssertionError("Wrong key type")
|
|
297
|
+
|
|
298
|
+
account = self.rpc.find_accounts({"accounts": [name]})["accounts"]
|
|
299
|
+
if not account:
|
|
300
|
+
return
|
|
301
|
+
if len(account) == 0:
|
|
302
|
+
return
|
|
303
|
+
if key_type == "memo":
|
|
304
|
+
key = self.getPrivateKeyForPublicKey(account[0]["memo_key"])
|
|
305
|
+
if key:
|
|
306
|
+
return [key]
|
|
307
|
+
else:
|
|
308
|
+
keys = []
|
|
309
|
+
key = None
|
|
310
|
+
for authority in account[0][key_type]["key_auths"]:
|
|
311
|
+
try:
|
|
312
|
+
key = self.getPrivateKeyForPublicKey(authority[0])
|
|
313
|
+
if key:
|
|
314
|
+
keys.append(key)
|
|
315
|
+
except MissingKeyError:
|
|
316
|
+
key = None
|
|
317
|
+
if not keys:
|
|
318
|
+
raise MissingKeyError("No private key for {} found".format(name))
|
|
319
|
+
return keys
|
|
320
|
+
return
|
|
321
|
+
|
|
322
|
+
def getOwnerKeyForAccount(self, name: str) -> Optional[str]:
|
|
323
|
+
"""Obtain owner Private Key for an account from the wallet database"""
|
|
324
|
+
return self.getKeyForAccount(name, "owner")
|
|
325
|
+
|
|
326
|
+
def getMemoKeyForAccount(self, name: str) -> Optional[str]:
|
|
327
|
+
"""Obtain owner Memo Key for an account from the wallet database"""
|
|
328
|
+
return self.getKeyForAccount(name, "memo")
|
|
329
|
+
|
|
330
|
+
def getActiveKeyForAccount(self, name: str) -> Optional[str]:
|
|
331
|
+
"""Obtain owner Active Key for an account from the wallet database"""
|
|
332
|
+
return self.getKeyForAccount(name, "active")
|
|
333
|
+
|
|
334
|
+
def getPostingKeyForAccount(self, name: str) -> Optional[str]:
|
|
335
|
+
"""Obtain owner Posting Key for an account from the wallet database"""
|
|
336
|
+
return self.getKeyForAccount(name, "posting")
|
|
337
|
+
|
|
338
|
+
def getOwnerKeysForAccount(self, name: str) -> Optional[List[str]]:
|
|
339
|
+
"""Obtain list of all owner Private Keys for an account from the wallet database"""
|
|
340
|
+
return self.getKeysForAccount(name, "owner")
|
|
341
|
+
|
|
342
|
+
def getActiveKeysForAccount(self, name: str) -> Optional[List[str]]:
|
|
343
|
+
"""Obtain list of all owner Active Keys for an account from the wallet database"""
|
|
344
|
+
return self.getKeysForAccount(name, "active")
|
|
345
|
+
|
|
346
|
+
def getPostingKeysForAccount(self, name: str) -> Optional[List[str]]:
|
|
347
|
+
"""Obtain list of all owner Posting Keys for an account from the wallet database"""
|
|
348
|
+
return self.getKeysForAccount(name, "posting")
|
|
349
|
+
|
|
350
|
+
def getAccountFromPrivateKey(self, wif: str) -> Optional[str]:
|
|
351
|
+
"""Obtain account name from private key"""
|
|
352
|
+
pub = self.publickey_from_wif(wif)
|
|
353
|
+
return self.getAccountFromPublicKey(pub)
|
|
354
|
+
|
|
355
|
+
def getAccountsFromPublicKey(self, pub: str) -> Generator[str, None, None]:
|
|
356
|
+
"""Obtain all account names associated with a public key
|
|
357
|
+
|
|
358
|
+
:param str pub: Public key
|
|
359
|
+
"""
|
|
360
|
+
if not self.blockchain.is_connected():
|
|
361
|
+
raise OfflineHasNoRPCException("No RPC available in offline mode!")
|
|
362
|
+
self.blockchain.rpc.set_next_node_on_empty_reply(False)
|
|
363
|
+
names = self.blockchain.rpc.get_key_references({"keys": [pub]})["accounts"]
|
|
364
|
+
for name in names:
|
|
365
|
+
yield from name
|
|
366
|
+
|
|
367
|
+
def getAccountFromPublicKey(self, pub: str) -> Optional[str]:
|
|
368
|
+
"""Obtain the first account name from public key
|
|
369
|
+
|
|
370
|
+
:param str pub: Public key
|
|
371
|
+
|
|
372
|
+
Note: this returns only the first account with the given key. To
|
|
373
|
+
get all accounts associated with a given public key, use
|
|
374
|
+
:func:`getAccountsFromPublicKey`.
|
|
375
|
+
"""
|
|
376
|
+
names = list(self.getAccountsFromPublicKey(pub))
|
|
377
|
+
if not names:
|
|
378
|
+
return None
|
|
379
|
+
else:
|
|
380
|
+
return names[0]
|
|
381
|
+
|
|
382
|
+
def getAllAccounts(self, pub: str) -> Generator[Dict[str, Any], None, None]:
|
|
383
|
+
"""Get the account data for a public key (all accounts found for this
|
|
384
|
+
public key)
|
|
385
|
+
|
|
386
|
+
:param str pub: Public key
|
|
387
|
+
"""
|
|
388
|
+
for name in self.getAccountsFromPublicKey(pub):
|
|
389
|
+
try:
|
|
390
|
+
account = Account(name, blockchain_instance=self.blockchain)
|
|
391
|
+
except AccountDoesNotExistsException:
|
|
392
|
+
continue
|
|
393
|
+
yield {
|
|
394
|
+
"name": account["name"],
|
|
395
|
+
"account": account,
|
|
396
|
+
"type": self.getKeyType(account, pub),
|
|
397
|
+
"pubkey": pub,
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
def getAccount(self, pub: str) -> Optional[Dict[str, Any]]:
|
|
401
|
+
"""Get the account data for a public key (first account found for this
|
|
402
|
+
public key)
|
|
403
|
+
|
|
404
|
+
:param str pub: Public key
|
|
405
|
+
"""
|
|
406
|
+
name = self.getAccountFromPublicKey(pub)
|
|
407
|
+
if not name:
|
|
408
|
+
return {"name": None, "type": None, "pubkey": pub}
|
|
409
|
+
else:
|
|
410
|
+
try:
|
|
411
|
+
account = Account(name, blockchain_instance=self.blockchain)
|
|
412
|
+
except Exception:
|
|
413
|
+
return
|
|
414
|
+
return {
|
|
415
|
+
"name": account["name"],
|
|
416
|
+
"account": account,
|
|
417
|
+
"type": self.getKeyType(account, pub),
|
|
418
|
+
"pubkey": pub,
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
def getKeyType(self, account: Union[Account, Dict[str, Any]], pub: str) -> Optional[str]:
|
|
422
|
+
"""Get key type
|
|
423
|
+
|
|
424
|
+
:param nectar.account.Account/dict account: Account data
|
|
425
|
+
:type account: Account, dict
|
|
426
|
+
:param str pub: Public key
|
|
427
|
+
|
|
428
|
+
"""
|
|
429
|
+
for authority in ["owner", "active", "posting"]:
|
|
430
|
+
for key in account[authority]["key_auths"]:
|
|
431
|
+
if str(pub) == key[0]:
|
|
432
|
+
return authority
|
|
433
|
+
if str(pub) == account["memo_key"]:
|
|
434
|
+
return "memo"
|
|
435
|
+
return None
|
|
436
|
+
|
|
437
|
+
def getAccounts(self) -> List[Dict[str, Any]]:
|
|
438
|
+
"""Return all accounts installed in the wallet database"""
|
|
439
|
+
pubkeys = self.getPublicKeys()
|
|
440
|
+
accounts = []
|
|
441
|
+
for pubkey in pubkeys:
|
|
442
|
+
# Filter those keys not for our network
|
|
443
|
+
if pubkey[: len(self.prefix)] == self.prefix:
|
|
444
|
+
accounts.extend(self.getAllAccounts(pubkey))
|
|
445
|
+
return accounts
|
|
446
|
+
|
|
447
|
+
def getPublicKeys(self, current: bool = False) -> List[str]:
|
|
448
|
+
"""Return all installed public keys
|
|
449
|
+
:param bool current: If true, returns only keys for currently
|
|
450
|
+
connected blockchain
|
|
451
|
+
"""
|
|
452
|
+
pubkeys = self.store.getPublicKeys()
|
|
453
|
+
if not current:
|
|
454
|
+
return pubkeys
|
|
455
|
+
pubs = []
|
|
456
|
+
for pubkey in pubkeys:
|
|
457
|
+
# Filter those keys not for our network
|
|
458
|
+
if pubkey[: len(self.prefix)] == self.prefix:
|
|
459
|
+
pubs.append(pubkey)
|
|
460
|
+
return pubs
|
|
461
|
+
|
|
462
|
+
def wipe(self, sure: bool = False) -> None:
|
|
463
|
+
if not sure:
|
|
464
|
+
log.error(
|
|
465
|
+
"You need to confirm that you are sure "
|
|
466
|
+
"and understand the implications of "
|
|
467
|
+
"wiping your wallet!"
|
|
468
|
+
)
|
|
469
|
+
return
|
|
470
|
+
else:
|
|
471
|
+
self.store.wipe()
|
|
472
|
+
self.store.wipe_masterpassword()
|