Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check transfer fee #1215

Merged
merged 6 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions bittensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
17 changes: 12 additions & 5 deletions bittensor/_subtensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,22 +112,29 @@ 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,
network = config.subtensor.get('network', bittensor.defaults.subtensor.network),
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),
Expand Down
38 changes: 35 additions & 3 deletions bittensor/_subtensor/extrinsics/transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -75,14 +78,42 @@ 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.
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..."):
Expand All @@ -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.
Expand Down
36 changes: 35 additions & 1 deletion bittensor/_subtensor/subtensor_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 ####
Expand Down Expand Up @@ -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. ####
Expand Down Expand Up @@ -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 """
Expand Down Expand Up @@ -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 ####
Expand Down