From 234f5f2deded6afa69d8a46f861531e4ac1ed4ad Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 22 Mar 2023 16:18:20 -0400 Subject: [PATCH 1/6] add existential check --- bittensor/_subtensor/subtensor_impl.py | 36 +++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/bittensor/_subtensor/subtensor_impl.py b/bittensor/_subtensor/subtensor_impl.py index e8c413c3d2..88e12a2b7a 100644 --- a/bittensor/_subtensor/subtensor_impl.py +++ b/bittensor/_subtensor/subtensor_impl.py @@ -241,6 +241,22 @@ def transfer( wait_for_finalization = wait_for_finalization, prompt = prompt ) + + def get_existential_deposit( + self, + block: Optional[int] = None, + ) -> Optional[Balance]: + """ Returns the existential deposit for the chain. """ + result = self.query_constant( + module_name='Balances', + constant_name='ExistentialDeposit', + block = block, + ) + + if result is None: + return None + + return Balance.from_rao(result.value) ################# #### Serving #### @@ -373,6 +389,18 @@ def make_substrate_call_with_retry(): block_hash = None if block == None else substrate.get_block_hash(block) ) return make_substrate_call_with_retry() + + """ Gets a constant from subtensor with module_name, constant_name, and block. """ + def query_constant( self, module_name: str, constant_name: str, block: Optional[int] = None ) -> Optional[object]: + @retry(delay=2, tries=3, backoff=2, max_delay=4) + def make_substrate_call_with_retry(): + with self.substrate as substrate: + return substrate.get_constant( + module_name=module_name, + constant_name=constant_name, + block_hash = None if block == None else substrate.get_block_hash(block) + ) + return make_substrate_call_with_retry() ##################################### #### Hyper parameter calls. #### @@ -484,7 +512,7 @@ def tempo (self, netuid: int, block: Optional[int] = None) -> int: return self.query_subtensor('Tempo', block, [netuid] ).value ########################## - #### Account fucntions ### + #### Account functions ### ########################## """ Returns the total stake held on a hotkey including delegative """ @@ -950,6 +978,12 @@ def metagraph( self, netuid: int, block: Optional[int] = None, lite: bool = True print("Metagraph subtensor: ", self.network) return metagraph + ################ + #### Transfer ## + ################ + + + ################ #### Legacy #### From ccf045b443751aab39be4ebe1fbb0bcc45e0f830 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 22 Mar 2023 16:18:30 -0400 Subject: [PATCH 2/6] add check existential and fee to transfer --- bittensor/_subtensor/extrinsics/transfer.py | 36 +++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/bittensor/_subtensor/extrinsics/transfer.py b/bittensor/_subtensor/extrinsics/transfer.py index 10266e537a..236b00a043 100644 --- a/bittensor/_subtensor/extrinsics/transfer.py +++ b/bittensor/_subtensor/extrinsics/transfer.py @@ -31,6 +31,7 @@ def transfer_extrinsic( 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 @@ -47,6 +48,8 @@ def transfer_extrinsic( 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: @@ -75,9 +78,37 @@ def transfer_extrinsic( # 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..."): + with subtensor.substrate as substrate: + call = substrate.compose_call( + call_module='Balances', + call_function='transfer', + call_params={ + 'dest': dest, + 'value': transfer_balance.rao + } + ) + + try: + payment_info = substrate.get_payment_info( call = call, keypair = wallet.coldkey ) + except Exception as e: + bittensor.__console__.print(":cross_mark: [red]Failed to get payment info[/red]:[bold white]\n {}[/bold white]".format(e)) + payment_info = { + 'partialFee': 2e7, # assume 0.02 Tao + } + + fee = bittensor.Balance.from_rao( payment_info['partialFee'] ) - if account_balance < transfer_balance: - bittensor.__console__.print(":cross_mark: [red]Not enough balance[/red]:[bold white]\n balance: {}\n amount: {}[/bold white]".format( account_balance, transfer_balance )) + 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. @@ -95,6 +126,7 @@ def transfer_extrinsic( 'value': transfer_balance.rao } ) + extrinsic = substrate.create_signed_extrinsic( call = call, keypair = wallet.coldkey ) response = substrate.submit_extrinsic( extrinsic, wait_for_inclusion = wait_for_inclusion, wait_for_finalization = wait_for_finalization ) # We only wait here if we expect finalization. From b15d2df602aeef663c87ef16a148a7d2df8612ed Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 22 Mar 2023 18:53:34 -0400 Subject: [PATCH 3/6] add fee mention --- bittensor/_subtensor/extrinsics/transfer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bittensor/_subtensor/extrinsics/transfer.py b/bittensor/_subtensor/extrinsics/transfer.py index 236b00a043..0fef39375b 100644 --- a/bittensor/_subtensor/extrinsics/transfer.py +++ b/bittensor/_subtensor/extrinsics/transfer.py @@ -113,7 +113,7 @@ def transfer_extrinsic( # Ask before moving on. if prompt: - if not Confirm.ask("Do you want to transfer:[bold white]\n amount: {}\n from: {}:{}\n to: {}[/bold white]".format( transfer_balance, wallet.name, wallet.coldkey.ss58_address, dest )): + 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..."): From 3985f38d262dd9387a803f1df45bcadb417a9c4c Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 22 Mar 2023 18:53:49 -0400 Subject: [PATCH 4/6] add type reg and remove delegate profile url --- bittensor/__init__.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bittensor/__init__.py b/bittensor/__init__.py index 54a6ca4882..20733f332b 100644 --- a/bittensor/__init__.py +++ b/bittensor/__init__.py @@ -100,9 +100,12 @@ def turn_console_off(): __mock_chain_db__ = './tmp/mock_chain_db' -# Delegate Profiles -__delegate_profiles_url__: str = 'https://raw.githubusercontent.com/opentensor/delegate_profiles/master/DELEGATES.md' - +# --- Type Registry --- +__type_registry__ = { + 'types': { + 'Balance': 'u64', # Need to override default u128 + }, +} # --- Prometheus --- __prometheus_version__ = "0.1.0" From b5ac33966991abc5389c194f693e7c2cb2335d34 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 22 Mar 2023 18:53:58 -0400 Subject: [PATCH 5/6] use type reg for finney nets --- bittensor/_subtensor/__init__.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/bittensor/_subtensor/__init__.py b/bittensor/_subtensor/__init__.py index e20f86c266..a17f61e3cc 100644 --- a/bittensor/_subtensor/__init__.py +++ b/bittensor/_subtensor/__init__.py @@ -112,15 +112,16 @@ def __new__( # make sure formatting is good endpoint_url = bittensor.utils.networking.get_formatted_ws_endpoint_url(endpoint_url) - substrate = SubstrateInterface( - ss58_format = bittensor.__ss58_format__, - use_remote_preset=True, - url = endpoint_url, - ) + subtensor.check_config( config ) network = config.subtensor.get('network', bittensor.defaults.subtensor.network) if network == 'nakamoto': + substrate = SubstrateInterface( + ss58_format = bittensor.__ss58_format__, + use_remote_preset=True, + url = endpoint_url, + ) # Use nakamoto-specific subtensor. return Nakamoto_subtensor( substrate = substrate, @@ -128,6 +129,12 @@ def __new__( chain_endpoint = config.subtensor.chain_endpoint, ) else: + substrate = SubstrateInterface( + ss58_format = bittensor.__ss58_format__, + use_remote_preset=True, + url = endpoint_url, + type_registry=bittensor.__type_registry__ + ) return subtensor_impl.Subtensor( substrate = substrate, network = config.subtensor.get('network', bittensor.defaults.subtensor.network), From 2d29526b52791128907f71ce97113fe7891d0673 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 22 Mar 2023 18:54:56 -0400 Subject: [PATCH 6/6] add spacing --- bittensor/_subtensor/extrinsics/transfer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bittensor/_subtensor/extrinsics/transfer.py b/bittensor/_subtensor/extrinsics/transfer.py index 0fef39375b..8b5ed9c7a7 100644 --- a/bittensor/_subtensor/extrinsics/transfer.py +++ b/bittensor/_subtensor/extrinsics/transfer.py @@ -113,7 +113,7 @@ def transfer_extrinsic( # 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 )): + 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..."):