def prepare_transaction(self, txn: TransactionAPI) -> TransactionAPI: """ Set default values on a transaction. Raises: :class:`~ape.exceptions.AccountsError`: When the account cannot afford the transaction or the nonce is invalid. :class:`~ape.exceptions.TransactionError`: When given negative required confirmations. Args: txn (:class:`~ape.api.transactions.TransactionAPI`): The transaction to prepare. Returns: :class:`~ape.api.transactions.TransactionAPI` """ # NOTE: Allow overriding nonce, assume user understand what this does if txn.nonce is None: txn.nonce = self.nonce elif txn.nonce < self.nonce: raise AccountsError("Invalid nonce, will not publish.") txn = self.provider.prepare_transaction(txn) if txn.total_transfer_value > self.balance: raise AccountsError( "Transfer value meets or exceeds account balance.\n" "Are you using the correct provider/account combination?\n" f"(transfer_value={txn.total_transfer_value}, balance={self.balance})." ) return txn
def get_user_selected_account( account_type: Optional[Type[AccountAPI]] = None, prompt_message: Optional[str] = None) -> AccountAPI: """ Prompt the user to pick from their accounts and return that account. Use this method if you want to prompt users to select accounts _outside_ of CLI options. For CLI options, use :meth:`~ape.cli.options.account_option`. Args: account_type (type[:class:`~ape.api.accounts.AccountAPI`], optional): If given, the user may only select an account of this type. prompt_message (str, optional): Customize the prompt message. Returns: :class:`~ape.api.accounts.AccountAPI` """ if account_type and not issubclass(account_type, AccountAPI): raise AccountsError( f"Cannot return accounts with type '{account_type}'.") prompt = AccountAliasPromptChoice(account_type=account_type, prompt_message=prompt_message) return prompt.get_user_selected_account()
def deploy(self, contract: "ContractContainer", *args, **kwargs) -> "ContractInstance": """ Create a smart contract on the blockchain. The smart contract must compile before deploying and a provider must be active. Args: contract (:class:`~ape.contracts.ContractContainer`): The type of contract to deploy. Returns: :class:`~ape.contracts.ContractInstance`: An instance of the deployed contract. """ txn = contract(*args, **kwargs) txn.sender = self.address receipt = self.call(txn) if not receipt.contract_address: raise AccountsError( f"'{receipt.txn_hash}' did not create a contract.") address = click.style(receipt.contract_address, bold=True) contract_name = contract.contract_type.name or "<Unnamed Contract>" logger.success(f"Contract '{contract_name}' deployed to: {address}") contract_instance = self.create_contract( address=receipt.contract_address, # type: ignore contract_type=contract.contract_type, ) self.chain_manager.contracts[ contract_instance.address] = contract_instance.contract_type return contract_instance
def get_user_selected_account(self) -> AccountAPI: """ Returns the selected account. Returns: :class:`~ape.api.accounts.AccountAPI` """ if not self.choices: raise AccountsError("No accounts found.") elif len(self.choices) == 1: return accounts.load(self.choices[0]) self.print_choices() return click.prompt(self._prompt_message, type=self)
def remove(self, account: AccountAPI): """ Delete an account. Raises: :class:`~ape.exceptions.AccountsError`: When the account is not known to ``ape``. Args: account (:class:`~ape.accounts.AccountAPI`): The account to remove. """ self._verify_account_type(account) if account.address not in self: raise AccountsError(f"Account '{account.address}' not known.") self.__delitem__(account.address)
def append(self, account: AccountAPI): """ Add an account to the container. Raises: :class:`~ape.exceptions.AccountsError`: When the account is already in the container. Args: account (:class:`~ape.api.accounts.AccountAPI`): The account to add. """ self._verify_account_type(account) if account.address in self: raise AccountsError( f"Account '{account.address}' already in container.") self._verify_unused_alias(account) self.__setitem__(account.address, account)
def _verify_account_type(self, account): if not isinstance(account, self.account_type): message = ( f"Container '{type(account).__name__}' is an incorrect " f"type for container '{type(self.account_type).__name__}'.") raise AccountsError(message)