From d5408d88ff2954a62681fe0ba252b83e6f7c984d Mon Sep 17 00:00:00 2001 From: Jakub Ziebinski <ziebinskijakub@gmail.com> Date: Fri, 28 Feb 2025 14:28:27 +0100 Subject: [PATCH] Implementation of the wrapper for wax --- package/test_tools/__init__.py | 2 + .../__private/wallet/create_accounts.py | 24 +- package/test_tools/__private/wallet/wallet.py | 115 ++---- .../test_tools/__private/wallet/wallet_api.py | 53 +-- package/test_tools/__private/wax_wrapper.py | 340 ++++++++++++++++++ 5 files changed, 406 insertions(+), 128 deletions(-) create mode 100644 package/test_tools/__private/wax_wrapper.py diff --git a/package/test_tools/__init__.py b/package/test_tools/__init__.py index c87230c22..5c7bf06a1 100644 --- a/package/test_tools/__init__.py +++ b/package/test_tools/__init__.py @@ -9,6 +9,7 @@ from test_tools.__private import ( constants, exceptions, paths_to_executables, + wax_wrapper, ) from test_tools.__private.account import Account, PrivateKey, PublicKey from test_tools.__private.alternate_chain_specs import AlternateChainSpecs, HardforkSchedule, InitialVesting @@ -58,6 +59,7 @@ __all__ = [ "OffsetTimeControl", "SpeedUpRateTimeControl", "StartTimeControl", + "wax_wrapper", ] if TYPE_CHECKING: diff --git a/package/test_tools/__private/wallet/create_accounts.py b/package/test_tools/__private/wallet/create_accounts.py index 23e30372a..468a8565f 100644 --- a/package/test_tools/__private/wallet/create_accounts.py +++ b/package/test_tools/__private/wallet/create_accounts.py @@ -9,7 +9,6 @@ from typing import TYPE_CHECKING, Any from loguru import logger -import wax from schemas.fields.compound import Authority from schemas.fields.hive_int import HiveInt from schemas.operations.account_create_operation import AccountCreateOperation @@ -21,8 +20,12 @@ from test_tools.__private.wallet.constants import ( SimpleTransaction, WalletResponseBase, ) -from wax._private.core.encoders import to_cpp_string -from wax._private.result_tools import expose_result_as_python_string +from test_tools.__private.wax_wrapper import ( + calculate_sig_digest, + calculate_transaction_id, + get_tapos_data, + validate_transaction, +) from wax.helpy._interfaces.asset.asset import Asset if TYPE_CHECKING: @@ -48,7 +51,7 @@ def generate_transaction_template(node: RemoteNode) -> SimpleTransaction: block_id = gdpo.head_block_id # set header - tapos_data = wax.get_tapos_data(block_id.encode()) + tapos_data = get_tapos_data(block_id) ref_block_num = tapos_data.ref_block_num ref_block_prefix = tapos_data.ref_block_prefix @@ -68,12 +71,10 @@ def generate_transaction_template(node: RemoteNode) -> SimpleTransaction: def sign_transaction( node: RemoteNode, transaction: SimpleTransaction, beekeeper_wallet: UnlockedWallet ) -> SimpleTransaction: - transaction_as_bytes = to_cpp_string(transaction.json()) - wax.calculate_transaction_id(transaction_as_bytes) + calculate_transaction_id(transaction) node_config = node.api.database.get_config() - wax_result = wax.calculate_sig_digest(transaction_as_bytes, to_cpp_string(node_config.HIVE_CHAIN_ID)) - sig_digest = expose_result_as_python_string(wax_result) + sig_digest = calculate_sig_digest(transaction, node_config.HIVE_CHAIN_ID) key_to_sign_with = beekeeper_wallet.import_key(private_key=Account("initminer").private_key) time_before = datetime.now() @@ -83,9 +84,7 @@ def sign_transaction( transaction.signatures.append(signature) transaction.signatures = list(set(transaction.signatures)) - - transaction_as_bytes = to_cpp_string(transaction.json()) - wax.validate_transaction(transaction_as_bytes) + validate_transaction(transaction) return transaction @@ -102,10 +101,9 @@ def prepare_transaction( operation.fee = account_creation_fee # type: ignore[assignment] transaction.add_operation(operation) transaction = sign_transaction(node, transaction, beekeeper_wallet) - transaction_as_bytes = to_cpp_string(transaction.json()) return WalletResponseBase( - transaction_id=expose_result_as_python_string(wax.calculate_transaction_id(transaction_as_bytes)), + transaction_id=calculate_transaction_id(transaction), ref_block_num=transaction.ref_block_num, ref_block_prefix=transaction.ref_block_prefix, expiration=transaction.expiration, diff --git a/package/test_tools/__private/wallet/wallet.py b/package/test_tools/__private/wallet/wallet.py index f2aeec1a9..0271a72db 100644 --- a/package/test_tools/__private/wallet/wallet.py +++ b/package/test_tools/__private/wallet/wallet.py @@ -9,7 +9,6 @@ from beekeepy import Beekeeper, Settings from beekeepy.communication import StrictOverseer from beekeepy.exceptions import ErrorInResponseError -import wax from schemas.fields.basic import PublicKey from schemas.fields.hex import Hex from schemas.fields.hive_int import HiveInt @@ -27,15 +26,23 @@ from test_tools.__private.wallet.constants import ( WalletResponse, WalletResponseBase, ) -from test_tools.__private.wallet.create_accounts import ( - create_accounts, -) +from test_tools.__private.wallet.create_accounts import create_accounts from test_tools.__private.wallet.single_transaction_context import SingleTransactionContext from test_tools.__private.wallet.wallet_api import Api -from wax._private.core.encoders import to_cpp_string, to_python_string -from wax._private.result_tools import expose_result_as_python_string +from test_tools.__private.wax_wrapper import ( + calculate_legacy_sig_digest, + calculate_legacy_transaction_id, + calculate_sig_digest, + calculate_transaction_id, + collect_signing_keys, + get_hive_protocol_config, + get_tapos_data, + minimize_required_signatures, + to_wax_authorities, + validate_transaction, + wax_authorities, +) from wax.helpy import Hf26Asset as Asset -from wax.wax_result import python_minimize_required_signatures_data if TYPE_CHECKING: from pathlib import Path @@ -43,11 +50,6 @@ if TYPE_CHECKING: from beekeepy._interface.abc.synchronous.session import Session from beekeepy._interface.abc.synchronous.wallet import UnlockedWallet - from schemas.apis.wallet_bridge_api.fundaments_of_responses import Account as AccountSchema - from schemas.fields.assets.hbd import AssetHbdHF26 - from schemas.fields.assets.hive import AssetHiveHF26 - from schemas.fields.assets.vests import AssetVestsHF26 - from schemas.fields.compound import Authority from schemas.operations import AnyOperation from test_tools.__private.user_handles.handles.wallet_handle import WalletHandle @@ -82,10 +84,8 @@ class Wallet(UserHandleImplementation, ScopedObject): self.run(preconfigure=preconfigure) if self.connected_node is not None: node_version = self.connected_node.api.database.get_version().node_type - protocol_config = { - key.decode(): value.decode() - for key, value in wax.get_hive_protocol_config(to_cpp_string(self.__get_chain_id())).items() - } + protocol_config = get_hive_protocol_config(self.__get_chain_id()) + is_testnet_wax = protocol_config["IS_TEST_NET"] if self._transaction_serialization == "legacy": if node_version == "testnet" and is_testnet_wax == "false": @@ -288,7 +288,7 @@ class Wallet(UserHandleImplementation, ScopedObject): block_id = gdpo.head_block_id # set header - tapos_data = wax.get_tapos_data(block_id.encode()) + tapos_data = get_tapos_data(block_id) ref_block_num = tapos_data.ref_block_num ref_block_prefix = tapos_data.ref_block_prefix @@ -327,11 +327,9 @@ class Wallet(UserHandleImplementation, ScopedObject): return WalletResponse( transaction_id=( - expose_result_as_python_string( - wax.calculate_transaction_id(self.__transaction_to_cpp_string(transaction)) - if self._transaction_serialization == "hf26" - else wax.calculate_legacy_transaction_id(self.__transaction_to_cpp_string(transaction)) - ) + calculate_transaction_id(transaction) + if self._transaction_serialization == "hf26" + else calculate_legacy_transaction_id(transaction) ), block_num=broadcast_response.block_num, transaction_num=broadcast_response.trx_num, @@ -347,13 +345,9 @@ class Wallet(UserHandleImplementation, ScopedObject): return WalletResponseBase( transaction_id=( - expose_result_as_python_string( - wax.calculate_transaction_id(self.__transaction_to_cpp_string(transaction)) - ) + calculate_transaction_id(transaction) if self._transaction_serialization == "hf26" - else expose_result_as_python_string( - wax.calculate_legacy_transaction_id(self.__transaction_to_cpp_string(transaction)) - ) + else calculate_legacy_transaction_id(transaction) ), ref_block_num=transaction.ref_block_num, ref_block_prefix=transaction.ref_block_prefix, @@ -375,13 +369,9 @@ class Wallet(UserHandleImplementation, ScopedObject): def calculate_sig_digest(self, transaction: SimpleTransaction) -> str: chain_id = self.__get_chain_id() return ( - expose_result_as_python_string( - wax.calculate_sig_digest(self.__transaction_to_cpp_string(transaction), to_cpp_string(chain_id)) - ) + calculate_sig_digest(transaction, chain_id) if self._transaction_serialization == "hf26" - else expose_result_as_python_string( - wax.calculate_legacy_sig_digest(self.__transaction_to_cpp_string(transaction), to_cpp_string(chain_id)) - ) + else calculate_legacy_sig_digest(transaction, chain_id) ) def sign_transaction( @@ -393,72 +383,38 @@ class Wallet(UserHandleImplementation, ScopedObject): transaction.signatures.append(signature) transaction.signatures = list(set(transaction.signatures)) - wax.validate_transaction(self.__transaction_to_cpp_string(transaction)) + validate_transaction(transaction) return transaction def reduce_signatures( self, transaction: SimpleTransaction, keys_to_sign_with: list[PublicKey], - retrived_authorities: dict[bytes, wax.python_authorities], + retrived_authorities: dict[bytes, wax_authorities], ) -> list[str] | list[Any]: def retrieve_witness_key(wittnes_name: bytes) -> bytes: get_witness = self._force_connected_node.api.wallet_bridge.get_witness(wittnes_name.decode()) assert get_witness is not None return get_witness.signing_key.encode() - return [ - to_python_string(pub_key) - for pub_key in wax.minimize_required_signatures( - self.__transaction_to_cpp_string(transaction), - python_minimize_required_signatures_data( - chain_id=to_cpp_string(self.__get_chain_id()), - available_keys=[to_cpp_string(key) for key in keys_to_sign_with], - authorities_map=retrived_authorities, - get_witness_key=retrieve_witness_key, - ), - ) - ] + return minimize_required_signatures( + transaction, self.__get_chain_id(), keys_to_sign_with, retrived_authorities, retrieve_witness_key + ) def import_required_keys( self, transaction: SimpleTransaction - ) -> tuple[list[PublicKey], dict[bytes, wax.python_authorities]]: - def list_to_dict(list_: list[Any]) -> dict[bytes, int]: - result: dict[bytes, int] = {} - for i in list_: - result[i[0].encode()] = i[1] - return result - - def to_python_authority(account_authority: Authority) -> wax.python_authority: - return wax.python_authority( - weight_threshold=account_authority.weight_threshold, - account_auths=list_to_dict(account_authority.account_auths), - key_auths=list_to_dict(account_authority.key_auths), - ) + ) -> tuple[list[PublicKey], dict[bytes, wax_authorities]]: + retrived_authorities: dict[bytes, wax_authorities] = {} - def to_python_authorities( - account_authorities: AccountSchema[AssetHiveHF26, AssetHbdHF26, AssetVestsHF26] - ) -> wax.python_authorities: - return wax.python_authorities( - active=to_python_authority(account_authorities.active), - owner=to_python_authority(account_authorities.owner), - posting=to_python_authority(account_authorities.posting), - ) - - retrived_authorities: dict[bytes, wax.python_authorities] = {} - - def retrieve_authorities(account_names: list[bytes]) -> dict[bytes, wax.python_authorities]: + def retrieve_authorities(account_names: list[bytes]) -> dict[bytes, wax_authorities]: accounts = self._force_connected_node.api.wallet_bridge.get_accounts( [account_name.decode() for account_name in account_names] ) - retrived_authoritity = {acc.name.encode(): to_python_authorities(acc) for acc in accounts} + retrived_authoritity = {acc.name.encode(): to_wax_authorities(acc) for acc in accounts} retrived_authorities.update(retrived_authoritity) return retrived_authoritity - keys_for_signing = [ - key.decode() - for key in wax.collect_signing_keys(self.__transaction_to_cpp_string(transaction), retrieve_authorities) - ] + keys_for_signing = collect_signing_keys(transaction, retrieve_authorities) if self._use_authority != {}: account_name = next(iter(self._use_authority.keys())) @@ -477,6 +433,3 @@ class Wallet(UserHandleImplementation, ScopedObject): if broadcast is None: broadcast = True return SingleTransactionContext(self, broadcast=broadcast, blocking=blocking) - - def __transaction_to_cpp_string(self, transaction: SimpleTransaction) -> bytes: - return to_cpp_string(transaction.json()) diff --git a/package/test_tools/__private/wallet/wallet_api.py b/package/test_tools/__private/wallet/wallet_api.py index 6afa0603b..983e80d37 100644 --- a/package/test_tools/__private/wallet/wallet_api.py +++ b/package/test_tools/__private/wallet/wallet_api.py @@ -6,7 +6,6 @@ from datetime import datetime, timedelta from functools import wraps from typing import TYPE_CHECKING, Any, ParamSpec, cast -from schemas.fields.assets.hive import AssetHiveHF26 from schemas.fields.basic import AccountName, EmptyList, PrivateKey, PublicKey from schemas.fields.compound import Authority, HbdExchangeRate, LegacyChainProperties, Proposal from schemas.operations import AnyOperation @@ -69,17 +68,15 @@ from test_tools.__private.wallet.constants import ( from test_tools.__private.wallet.create_accounts import ( get_authority, ) -from wax import ( +from test_tools.__private.wax_wrapper import ( calculate_public_key, - create_wax_foundation, decode_encrypted_memo, encode_encrypted_memo, generate_password_based_private_key, suggest_brain_key, ) -from wax._private.core.encoders import to_cpp_string, to_python_string +from test_tools.__private.wax_wrapper import estimate_hive_collateral as wax_estimate_hive_collateral from wax._private.exceptions import WaxValidationFailedError -from wax._private.result_tools import expose_result_as_python_string, validate_wax_result from wax.helpy import Hf26Asset as Asset if TYPE_CHECKING: @@ -118,6 +115,7 @@ if TYPE_CHECKING: ) from schemas.fields.assets._base import AssetHF26 from schemas.fields.assets.hbd import AssetHbdHF26 + from schemas.fields.assets.hive import AssetHiveHF26 from schemas.fields.assets.vests import AssetVestsHF26 from schemas.fields.hex import Hex from schemas.fields.hive_int import HiveInt @@ -245,9 +243,7 @@ class Api: def __check_memo(self, account: AccountNameApiType, memo: str) -> None: if isinstance(memo, PrivateKey): try: - wax_result = calculate_public_key(wif=to_cpp_string(memo)) - validate_wax_result(wax_result) - public_key = expose_result_as_python_string(wax_result) + public_key = calculate_public_key(wif=memo) except WaxValidationFailedError: return get_account = self.get_account(account_name=account) @@ -842,11 +838,11 @@ class Api: :param only_result: This argument is no longer active and should not be provided. :return: The decrypted memo. """ - encrypted_memo = decode_encrypted_memo(to_cpp_string(memo)) + encrypted_memo = decode_encrypted_memo(memo) decrypt_memo = self.__wallet.beekeeper_wallet.decrypt_data( - from_key=to_python_string(encrypted_memo.main_encryption_key), # type: ignore[arg-type] - to_key=to_python_string(encrypted_memo.other_encryption_key), # type: ignore[arg-type] - content=to_python_string(encrypted_memo.encrypted_content), + from_key=PublicKey(encrypted_memo.main_encryption_key), + to_key=PublicKey(encrypted_memo.other_encryption_key), + content=encrypted_memo.encrypted_content, ) if decrypt_memo.startswith("#"): @@ -1165,19 +1161,10 @@ class Api: :param only_result: This argument is no longer active and should not be provided. :return: Estimated hive collateral. """ - wax_base_api = create_wax_foundation() current_median_history = self.get_feed_history().current_median_history current_min_history = self.get_feed_history().current_min_history - wax_asset = wax_base_api.estimate_hive_collateral( - current_median_history.base.dict(), - current_median_history.quote.dict(), - current_min_history.base.dict(), - current_min_history.quote.dict(), - hbd_amount_to_get.dict(), - ) - - return AssetHiveHF26(amount=int(wax_asset.amount), nai=wax_asset.nai, precision=wax_asset.precision) + return wax_estimate_hive_collateral(hbd_amount_to_get, current_median_history, current_min_history) @warn_if_only_result_set() def exit(self, only_result: bool | None = None) -> None: # noqa: ARG002 A003 @@ -1395,14 +1382,12 @@ class Api: ) encrypted_memo = proxy_encrypt_data(from_account.memo_key, to_account.memo_key, memo) - encoded_encrypted_memo = encode_encrypted_memo( - encrypted_content=to_cpp_string(encrypted_memo), - main_encryption_key=to_cpp_string(from_account.memo_key), - other_encryption_key=to_cpp_string(to_account.memo_key), + return encode_encrypted_memo( + encrypted_content=encrypted_memo, + main_encryption_key=from_account.memo_key, + other_encryption_key=to_account.memo_key, ) - return to_python_string(encoded_encrypted_memo) - @warn_if_only_result_set() def get_feed_history(self, only_result: bool | None = None) -> GetFeedHistory: # noqa: ARG002 """ @@ -1484,8 +1469,8 @@ class Api: :param only_result: This argument is no longer active and should not be provided. :return: A list containing the associated public key and the private key in WIF format. """ - wax_result = generate_password_based_private_key(account=account, role=role, password=password) - return [to_python_string(wax_result.associated_public_key), to_python_string(wax_result.wif_private_key)] + result = generate_password_based_private_key(account=account, role=role, password=password) + return [result.associated_public_key, result.wif_private_key] @warn_if_only_result_set() def get_prototype_operation( @@ -2151,12 +2136,12 @@ class Api: :param only_result: This argument is no longer active and should not be provided. :return: A dictionary containing the suggested brain key, associated WIF private key, and public key. """ - wax_result = suggest_brain_key() + result = suggest_brain_key() return { - "brain_priv_key": to_python_string(wax_result.brain_key), - "wif_priv_key": to_python_string(wax_result.wif_private_key), - "pub_key": to_python_string(wax_result.associated_public_key), + "brain_priv_key": result.brain_key, + "wif_priv_key": result.wif_private_key, + "pub_key": result.associated_public_key, } @require_unlocked_wallet diff --git a/package/test_tools/__private/wax_wrapper.py b/package/test_tools/__private/wax_wrapper.py new file mode 100644 index 000000000..075653117 --- /dev/null +++ b/package/test_tools/__private/wax_wrapper.py @@ -0,0 +1,340 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import TYPE_CHECKING, Any + +from schemas.fields.assets.hive import AssetHiveHF26 +from wax import create_wax_foundation +from wax._private.result_tools import ( + expose_result_as_python_string, + to_cpp_string, + to_python_string, + validate_wax_result, +) +from wax.cpp_python_bridge import calculate_legacy_sig_digest as wax_calculate_legacy_sig_digest +from wax.cpp_python_bridge import calculate_legacy_transaction_id as wax_calculate_legacy_transaction_id +from wax.cpp_python_bridge import calculate_public_key as wax_calculate_public_key +from wax.cpp_python_bridge import calculate_sig_digest as wax_calculate_sig_digest +from wax.cpp_python_bridge import calculate_transaction_id as wax_calculate_transaction_id +from wax.cpp_python_bridge import collect_signing_keys as wax_collect_signing_keys +from wax.cpp_python_bridge import decode_encrypted_memo as wax_decode_encrypted_memo +from wax.cpp_python_bridge import encode_encrypted_memo as wax_encode_encrypted_memo +from wax.cpp_python_bridge import generate_password_based_private_key as wax_generate_password_based_private_key +from wax.cpp_python_bridge import get_hive_protocol_config as wax_get_hive_protocol_config +from wax.cpp_python_bridge import get_tapos_data as wax_get_tapos_data +from wax.cpp_python_bridge import minimize_required_signatures as wax_minimize_required_signatures +from wax.cpp_python_bridge import validate_transaction as wax_validate_transaction +from wax.wax_result import ( + python_authorities, + python_authority, + python_minimize_required_signatures_data, +) + +if TYPE_CHECKING: + from collections.abc import Callable + + from schemas.apis.wallet_bridge_api.fundaments_of_responses import Account as AccountSchema + from schemas.fields.assets.hbd import AssetHbdHF26 + from schemas.fields.assets.vests import AssetVestsHF26 + from schemas.fields.basic import PublicKey + from schemas.fields.compound import Authority, Price + from schemas.transaction import Transaction + from test_tools.__private.wallet.constants import AccountNameApiType + from wax.models.key_data import IBrainKeyData + from wax.wax_result import python_ref_block_data + + +wax_authorities = python_authorities +wax_authority = python_authority + + +@dataclass +class WaxPrivateKeyData: + wif_private_key: str + associated_public_key: str + + +@dataclass +class WaxEncryptedMemo: + main_encryption_key: str + other_encryption_key: str + encrypted_content: str + + +def to_wax_authority(account_authority: Authority) -> wax_authority: + """ + Convert the given account authority (api form) to python authority (wax form). + + Args: + ---- + account_authority: The authority (not account!) object returned from the API. + """ + + def list_to_dict(list_: list[Any]) -> dict[bytes, int]: + result: dict[bytes, int] = {} + for i in list_: + result[i[0].encode()] = i[1] + return result + + return wax_authority( + weight_threshold=account_authority.weight_threshold, + account_auths=list_to_dict(account_authority.account_auths), + key_auths=list_to_dict(account_authority.key_auths), + ) + + +def to_wax_authorities( + account_authorities: AccountSchema[AssetHiveHF26, AssetHbdHF26, AssetVestsHF26] +) -> wax_authorities: + """ + Convert the given account authorities (api form) to python authorities (wax form). + + Args: + ---- + account_authorities: The account object returned from the API. + + Returns: + ------- + The converted python authorities. + """ + return wax_authorities( + active=to_wax_authority(account_authorities.active), + owner=to_wax_authority(account_authorities.owner), + posting=to_wax_authority(account_authorities.posting), + ) + + +def calculate_public_key(wif: str) -> str: + result = wax_calculate_public_key(to_cpp_string(wif)) + validate_wax_result(result) + return expose_result_as_python_string(result) + + +def get_tapos_data(head_block_id: str) -> python_ref_block_data: + return wax_get_tapos_data(to_cpp_string(head_block_id)) + + +def validate_transaction(transaction: Transaction) -> None: + """ + Validate the given transaction. + + Args: + ---- + transaction: The transaction to validate. + + Raises: + ------ + WaxValidationError: If the transaction is invalid. + """ + result = wax_validate_transaction(to_cpp_string(transaction.json())) + validate_wax_result(result) + + +def calculate_transaction_id(transaction: Transaction) -> str: + """ + Calculate the transaction id from the given transaction. + + Args: + ---- + transaction: The transaction to calculate the id for. + + Returns: + ------- + The calculated transaction id. + + Raises: + ------ + WaxValidationError: If the transaction id could not be calculated. + """ + result = wax_calculate_transaction_id(to_cpp_string(transaction.json())) + validate_wax_result(result) + return expose_result_as_python_string(result) + + +def calculate_legacy_transaction_id(transaction: Transaction) -> str: + """ + Calculate the transaction id from the given transaction in the legacy format. + + Args: + ---- + transaction: The transaction to calculate the id for. + + Returns: + ------- + The calculated transaction id in the legacy format. + + Raises: + ------ + WaxValidationError: If the transaction id could not be calculated. + """ + result = wax_calculate_legacy_transaction_id(to_cpp_string(transaction.json())) + validate_wax_result(result) + return expose_result_as_python_string(result) + + +def calculate_sig_digest(transaction: Transaction, chain_id: str) -> str: + """ + Calculate the sig digest from the given transaction and chain id. + + Args: + ---- + transaction: The transaction to calculate the sig digest for. + chain_id: The chain id to calculate the sig digest for. + + Returns: + ------- + The calculated signature digest. + + Raises: + ------ + WaxValidationError: If the signature digest could not be calculated. + """ + result = wax_calculate_sig_digest(to_cpp_string(transaction.json()), to_cpp_string(chain_id)) + validate_wax_result(result) + return expose_result_as_python_string(result) + + +def calculate_legacy_sig_digest(transaction: Transaction, chain_id: str) -> str: + """ + Calculate the sig digest from the given transaction and chain id in the legacy format. + + Args: + ---- + transaction: The transaction to calculate the sig digest for. + chain_id: The chain id to calculate the sig digest for. + + Returns: + ------- + The calculated signature digest in the legacy format. + + Raises: + ------ + WaxValidationError: If the sig digest could not be calculated. + """ + result = wax_calculate_legacy_sig_digest(to_cpp_string(transaction.json()), to_cpp_string(chain_id)) + validate_wax_result(result) + return expose_result_as_python_string(result) + + +def get_hive_protocol_config(chain_id: str) -> dict[str, str]: + return { + to_python_string(key): to_python_string(value) + for key, value in wax_get_hive_protocol_config(to_cpp_string(chain_id)).items() + } + + +def minimize_required_signatures( + transaction: Transaction, + chain_id: str, + available_keys: list[PublicKey], + retrived_authorities: dict[bytes, wax_authorities], + get_witness_key: Callable[[bytes], bytes], +) -> list[str]: + """ + Minimize the required signatures for the given transaction. + + Args: + ---- + transaction: The transaction to minimize the required signatures for. + chain_id: chain id of the current chain type. + available_keys: The available keys. + retrived_authorities: The retrieved authorities. + get_witness_key: The callable object to get the witness key. + + Returns: + ------- + The minimized required signatures. + """ + result = wax_minimize_required_signatures( + to_cpp_string(transaction.json()), + minimize_required_signatures_data=python_minimize_required_signatures_data( + chain_id=to_cpp_string(chain_id), + available_keys=[to_cpp_string(key) for key in available_keys], + authorities_map=retrived_authorities, + get_witness_key=get_witness_key, + ), + ) + return [to_python_string(signature) for signature in result] + + +def collect_signing_keys( + transaction: Transaction, retrieve_authorities: Callable[[list[bytes]], dict[bytes, wax_authorities]] +) -> list[str]: + """ + Collect the signing keys for the given transaction. + + Args: + ---- + transaction: The transaction to collect the signing keys for. + retrieve_authorities: The callable to retrieve the authorities. + + Returns: + ------- + The collected signing keys. + """ + return [ + to_python_string(key) + for key in wax_collect_signing_keys(to_cpp_string(transaction.json()), retrieve_authorities) + ] + + +def estimate_hive_collateral( + hbd_amount_to_get: AssetHbdHF26, + current_median_history: Price[AssetHiveHF26, AssetHbdHF26, AssetVestsHF26], + current_min_history: Price[AssetHiveHF26, AssetHbdHF26, AssetVestsHF26], +) -> AssetHiveHF26: + """ + Estimate the hive collateral for the given HBD amount to get. + + Args: + ---- + _____ + hbd_amount_to_get: The HBD amount to get. + current_median_history: The current median history (from the `get_feed_history`). + current_min_history: The current min history (from the `get_feed_history`). + + Returns: + ------- + The estimated hive collateral. + """ + wax_base_api = create_wax_foundation() + wax_asset = wax_base_api.estimate_hive_collateral( + current_median_history.base.dict(), + current_median_history.quote.dict(), + current_min_history.base.dict(), + current_min_history.quote.dict(), + hbd_amount_to_get.dict(), + ) + return AssetHiveHF26(amount=int(wax_asset.amount), nai=wax_asset.nai, precision=wax_asset.precision) + + +def generate_password_based_private_key(account: AccountNameApiType, role: str, password: str) -> WaxPrivateKeyData: + """Generate a password based private key for the given account and role.""" + wax_result = wax_generate_password_based_private_key(account, role, password) + return WaxPrivateKeyData( + wif_private_key=to_python_string(wax_result.wif_private_key), + associated_public_key=to_python_string(wax_result.associated_public_key), + ) + + +def suggest_brain_key() -> IBrainKeyData: + """Suggest a brain key.""" + wax_base_api = create_wax_foundation() + return wax_base_api.suggest_brain_key() + + +def decode_encrypted_memo(encoded_memo: str) -> WaxEncryptedMemo: + wax_result = wax_decode_encrypted_memo(to_cpp_string(encoded_memo)) + return WaxEncryptedMemo( + main_encryption_key=to_python_string(wax_result.main_encryption_key), + other_encryption_key=to_python_string(wax_result.other_encryption_key), + encrypted_content=to_python_string(wax_result.encrypted_content), + ) + + +def encode_encrypted_memo(encrypted_content: str, main_encryption_key: str, other_encryption_key: str = "") -> str: + return to_python_string( + wax_encode_encrypted_memo( + to_cpp_string(encrypted_content), to_cpp_string(main_encryption_key), to_cpp_string(other_encryption_key) + ) + ) -- GitLab