Skip to content

Commit

Permalink
Check transfer fee (#1215)
Browse files Browse the repository at this point in the history
* add existential check

* add check existential and fee to transfer

* add fee mention

* add type reg and remove delegate profile url

* use type reg for finney nets

* add spacing
  • Loading branch information
camfairchild authored Mar 22, 2023
1 parent adab6ec commit 893fa24
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 12 deletions.
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

0 comments on commit 893fa24

Please sign in to comment.