Source code for pypergraph.keyring.wallets.multi_account_wallet

from typing import Optional, List, Dict, Any

from pydantic import Field, model_serializer, model_validator, BaseModel

from pypergraph.core import BIP_44_PATHS, KeyringAssetType, KeyringWalletType, NetworkId

from .shared import sid_manager
from ..bip_helpers.bip39_helper import Bip39Helper
from ..keyrings.hd_keyring import HdKeyring


[docs] class MultiAccountWallet(BaseModel): type: str = Field(default=KeyringWalletType.MultiAccountWallet.value) id: str = Field(default=None) supported_assets: List[str] = Field(default=[]) label: Optional[str] = Field(default=None, max_length=12) keyring: HdKeyring = Field(default=None) mnemonic: Optional[str] = Field(default=None) network: str = Field(default=None)
[docs] @model_validator(mode="after") def compute_id(self): """Automatically computes the id based on injected SID value.""" self.id = sid_manager.next_sid(self.type) return self
[docs] @model_serializer def model_serialize(self) -> Dict[str, Any]: """Returns a serialized version of the object.""" return { "type": self.type, "label": self.label, "network": self.network, "secret": self.export_secret_key(), "rings": [self.keyring.model_serialize()], }
[docs] def create( self, network: str, label: str, num_of_accounts: int = 1, mnemonic: Optional[str] = None, ): """ Creates a wallet with a keyring of hierarchical deterministic accounts based on the number BIP44 indexes (num_of_accounts). :param network: "Constellation" or "Ethereum". :param label: Name of the wallet. :param num_of_accounts: Number of BIP44 indexes (accounts) to create. :param mnemonic: Mnemonic phrase. """ bip39 = Bip39Helper() self.mnemonic = mnemonic or bip39.generate_mnemonic() if not bip39.is_valid(self.mnemonic): raise ValueError("MultiAccountWallet :: Not a valid mnemonic phrase.") self.deserialize( secret=self.mnemonic, label=label, network=network, num_of_accounts=num_of_accounts, )
[docs] def set_label(self, val: str): """ Sets the name of the wallet. :param val: The name of the wallet. """ if not val: raise ValueError("MultiAccountWallet :: No label set.") self.label = val
[docs] def get_label(self) -> str: """ Get the name of the wallet. :return: The wallet name. """ return self.label
[docs] def get_network(self) -> str: return self.network
[docs] def get_state(self) -> Dict[str, Any]: return { "id": self.id, "type": self.type, "label": self.label, "supported_assets": self.supported_assets, "accounts": [a.get_state() for a in self.get_accounts()], }
[docs] def deserialize( self, label: str, network: str, secret: str, num_of_accounts: int, rings: Optional[List] = None, ): keyring = HdKeyring() self.set_label(label) self.network = network self.mnemonic = secret if self.network == NetworkId.Constellation.value: self.supported_assets.append(KeyringAssetType.DAG.value) bip44_path = BIP_44_PATHS.CONSTELLATION_PATH else: self.supported_assets.append(KeyringAssetType.ETH.value) self.supported_assets.append(KeyringAssetType.ERC20.value) bip44_path = BIP_44_PATHS.ETH_WALLET_PATH.value self.keyring = keyring.create( mnemonic=self.mnemonic, hd_path=bip44_path, network=self.network, number_of_accounts=num_of_accounts, ) rings = rings or self.model_serialize().get("rings") if rings: self.keyring.deserialize(rings[0])
[docs] @staticmethod def import_account(): """Importing is not supported.""" raise ValueError( "MultiAccountWallet :: Multi account wallets does not support import account." )
[docs] def get_accounts(self) -> List: """ Get list of MAW accounts. :return: List of MAW accounts with signing key. """ return self.keyring.get_accounts()
[docs] def get_account_by_address(self, address: str): """ Get the account matching the specified address. :param address: The address for the wanted account. """ return self.keyring.get_account_by_address(address)
[docs] def add_account(self): self.keyring.add_account_at()
[docs] def set_num_of_accounts(self, num: int): if not num: raise ValueError("MultiAccountWallet :: No number of account specified.") keyring = HdKeyring() self.keyring = keyring.create( mnemonic=self.mnemonic, hd_path=self.keyring.get_hd_path(), network=self.network, number_of_accounts=num, )
[docs] def remove_account(self, account): """ Remove a specific account. :param account: The account to be removed. """ self.keyring.remove_account(account)
[docs] def export_secret_key(self) -> str: return self.mnemonic
[docs] @staticmethod def reset_sid(): sid_manager.reset_sid()