Source code for bittensor.extrinsics.transfer

# The MIT License (MIT)
# Copyright © 2021 Yuma Rao
# Copyright © 2023 Opentensor Foundation

# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
# documentation files (the “Software”), to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
# the Software.

# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

import bittensor

from rich.prompt import Confirm
from typing import Union
from ..utils.balance import Balance
from ..utils import is_valid_bittensor_address_or_public_key


[docs] def transfer_extrinsic( subtensor: "bittensor.subtensor", wallet: "bittensor.wallet", dest: str, amount: Union[Balance, float], wait_for_inclusion: bool = True, wait_for_finalization: bool = False, keep_alive: bool = True, prompt: bool = False, ) -> bool: r"""Transfers funds from this wallet to the destination public key address. Args: wallet (bittensor.wallet): Bittensor wallet object to make transfer from. dest (str, ss58_address or ed25519): Destination public key address of reciever. amount (Union[Balance, int]): Amount to stake as Bittensor balance, or ``float`` interpreted as Tao. wait_for_inclusion (bool): If set, waits for the extrinsic to enter a block before returning ``true``, or returns ``false`` if the extrinsic fails to enter the block within the timeout. wait_for_finalization (bool): If set, waits for the extrinsic to be finalized on the chain before returning ``true``, or returns ``false`` if the extrinsic fails to be finalized within the timeout. keep_alive (bool): If set, keeps the account alive by keeping the balance above the existential deposit. prompt (bool): If ``true``, the call waits for confirmation from the user before proceeding. Returns: success (bool): Flag is ``true`` if extrinsic was finalized or uncluded in the block. If we did not wait for finalization / inclusion, the response is ``true``. """ # Validate destination address. if not is_valid_bittensor_address_or_public_key(dest): bittensor.__console__.print( ":cross_mark: [red]Invalid destination address[/red]:[bold white]\n {}[/bold white]".format( dest ) ) return False if isinstance(dest, bytes): # Convert bytes to hex string. dest = "0x" + dest.hex() try: # Unlock wallet coldkey. wallet.coldkey except bittensor.KeyFileError: bittensor.__console__.print( ":cross_mark: [red]Keyfile is corrupt, non-writable, non-readable or the password used to decrypt is invalid[/red]:[bold white]\n [/bold white]" ) return False # Convert to bittensor.Balance if not isinstance(amount, bittensor.Balance): transfer_balance = bittensor.Balance.from_tao(amount) else: transfer_balance = amount # Check balance. with bittensor.__console__.status(":satellite: Checking Balance..."): account_balance = subtensor.get_balance(wallet.coldkey.ss58_address) # check existential deposit. existential_deposit = subtensor.get_existential_deposit() with bittensor.__console__.status(":satellite: Transferring..."): fee = subtensor.get_transfer_fee( wallet=wallet, dest=dest, value=transfer_balance.rao ) if not keep_alive: # Check if the transfer should keep_alive the account existential_deposit = bittensor.Balance(0) # Check if we have enough balance. if account_balance < (transfer_balance + fee + existential_deposit): bittensor.__console__.print( ":cross_mark: [red]Not enough balance[/red]:[bold white]\n balance: {}\n amount: {}\n for fee: {}[/bold white]".format( account_balance, transfer_balance, fee ) ) return False # Ask before moving on. if prompt: if not Confirm.ask( "Do you want to transfer:[bold white]\n amount: {}\n from: {}:{}\n to: {}\n for fee: {}[/bold white]".format( transfer_balance, wallet.name, wallet.coldkey.ss58_address, dest, fee ) ): return False with bittensor.__console__.status(":satellite: Transferring..."): success, block_hash, err_msg = subtensor._do_transfer( wallet, dest, transfer_balance, wait_for_finalization=wait_for_finalization, wait_for_inclusion=wait_for_inclusion, ) if success: bittensor.__console__.print( ":white_heavy_check_mark: [green]Finalized[/green]" ) bittensor.__console__.print( "[green]Block Hash: {}[/green]".format(block_hash) ) explorer_urls = bittensor.utils.get_explorer_url_for_network( subtensor.network, block_hash, bittensor.__network_explorer_map__ ) if explorer_urls != {} and explorer_urls: bittensor.__console__.print( "[green]Opentensor Explorer Link: {}[/green]".format( explorer_urls.get("opentensor") ) ) bittensor.__console__.print( "[green]Taostats Explorer Link: {}[/green]".format( explorer_urls.get("taostats") ) ) else: bittensor.__console__.print(f":cross_mark: [red]Failed[/red]: {err_msg}") if success: with bittensor.__console__.status(":satellite: Checking Balance..."): new_balance = subtensor.get_balance(wallet.coldkey.ss58_address) bittensor.__console__.print( "Balance:\n [blue]{}[/blue] :arrow_right: [green]{}[/green]".format( account_balance, new_balance ) ) return True return False