diff --git a/bittensor/core/async_subtensor.py b/bittensor/core/async_subtensor.py index 23f23f5a6e..8b7e00c2a1 100644 --- a/bittensor/core/async_subtensor.py +++ b/bittensor/core/async_subtensor.py @@ -111,10 +111,10 @@ serve_axon_extrinsic, ) from bittensor.core.extrinsics.asyncex.staking import ( + add_stake_burn_extrinsic, add_stake_extrinsic, add_stake_multiple_extrinsic, set_auto_stake_extrinsic, - subnet_buyback_extrinsic, ) from bittensor.core.extrinsics.asyncex.start_call import start_call_extrinsic from bittensor.core.extrinsics.asyncex.take import set_take_extrinsic @@ -6419,14 +6419,13 @@ async def add_stake( wait_for_revealed_execution=wait_for_revealed_execution, ) - async def add_liquidity( + async def add_stake_burn( self, wallet: "Wallet", netuid: int, - liquidity: Balance, - price_low: Balance, - price_high: Balance, - hotkey_ss58: Optional[str] = None, + hotkey_ss58: str, + amount: Balance, + limit_price: Optional[Balance] = None, *, mev_protection: bool = DEFAULT_MEV_PROTECTION, period: Optional[int] = DEFAULT_PERIOD, @@ -6436,41 +6435,40 @@ async def add_liquidity( wait_for_revealed_execution: bool = True, ) -> ExtrinsicResponse: """ - Adds liquidity to the specified price range. + Executes a subnet buyback by staking TAO and immediately burning the resulting Alpha. + + Only the subnet owner can call this method, and it is rate-limited to one call per subnet tempo. Parameters: - wallet: The wallet used to sign the extrinsic (must be unlocked). - netuid: The UID of the target subnet for which the call is being initiated. - liquidity: The amount of liquidity to be added. - price_low: The lower bound of the price tick range. In TAO. - price_high: The upper bound of the price tick range. In TAO. - hotkey_ss58: The hotkey with staked TAO in Alpha. If not passed then the wallet hotkey is used. + wallet: The wallet used to sign the extrinsic (must be the subnet owner). + netuid: The unique identifier of the subnet. + hotkey_ss58: The `SS58` address of the hotkey account to stake to. + amount: The amount of TAO to use for the buyback. + limit_price: Optional limit price expressed in units of RAO per one Alpha. mev_protection: If `True`, encrypts and submits the transaction through the MEV Shield pallet to protect against front-running and MEV attacks. The transaction remains encrypted in the mempool until validators decrypt and execute it. If `False`, submits the transaction directly without encryption. - period: The number of blocks during which the transaction will remain valid after it's submitted. If - the transaction is not included in a block within that number of blocks, it will expire and be rejected. - You can think of it as an expiration date for the transaction. + period: The number of blocks during which the transaction will remain valid after it's submitted. If the + transaction is not included in a block within that number of blocks, it will expire and be rejected. You + can think of it as an expiration date for the transaction. raise_error: Raises a relevant exception rather than returning `False` if unsuccessful. - wait_for_inclusion: Whether to wait for the extrinsic to be included in a block. - wait_for_finalization: Whether to wait for finalization of the extrinsic. + wait_for_inclusion: Whether to wait for the inclusion of the transaction. + wait_for_finalization: Whether to wait for the finalization of the transaction. wait_for_revealed_execution: Whether to wait for the revealed execution of transaction if mev_protection used. Returns: ExtrinsicResponse: The result object of the extrinsic execution. - - Note: - Adding is allowed even when user liquidity is enabled in specified subnet. Call `toggle_user_liquidity` - method to enable/disable user liquidity. """ - return await add_liquidity_extrinsic( + check_balance_amount(amount) + if limit_price is not None: + check_balance_amount(limit_price) + return await add_stake_burn_extrinsic( subtensor=self, wallet=wallet, netuid=netuid, - liquidity=liquidity, - price_low=price_low, - price_high=price_high, hotkey_ss58=hotkey_ss58, + amount=amount, + limit_price=limit_price, mev_protection=mev_protection, period=period, raise_error=raise_error, @@ -6479,10 +6477,12 @@ async def add_liquidity( wait_for_revealed_execution=wait_for_revealed_execution, ) - async def announce_coldkey_swap( + async def add_stake_multiple( self, wallet: "Wallet", - new_coldkey_ss58: str, + netuids: UIDs, + hotkey_ss58s: list[str], + amounts: list[Balance], *, mev_protection: bool = DEFAULT_MEV_PROTECTION, period: Optional[int] = DEFAULT_PERIOD, @@ -6492,41 +6492,38 @@ async def announce_coldkey_swap( wait_for_revealed_execution: bool = True, ) -> ExtrinsicResponse: """ - Announces a coldkey swap by submitting the BlakeTwo256 hash of the new coldkey. - - This method allows a coldkey to declare its intention to swap to a new coldkey address. The announcement must be - made before the actual swap can be executed, and a delay period must pass before execution is allowed. - After making an announcement, all transactions from the coldkey are blocked except for `swap_coldkey_announced`. + Adds stakes to multiple neurons identified by their hotkey SS58 addresses. + This bulk operation allows for efficient staking across different neurons from a single wallet. Parameters: - wallet: Bittensor wallet object (should be the current coldkey wallet). - new_coldkey_ss58: SS58 address of the new coldkey that will replace the current one. - mev_protection: If ``True``, encrypts and submits the transaction through the MEV Shield pallet to protect + wallet: The wallet used for staking. + netuids: List of subnet UIDs. + hotkey_ss58s: List of `SS58` addresses of hotkeys to stake to. + amounts: List of corresponding TAO amounts to bet for each netuid and hotkey. + mev_protection: If `True`, encrypts and submits the transaction through the MEV Shield pallet to protect against front-running and MEV attacks. The transaction remains encrypted in the mempool until validators - decrypt and execute it. If ``False``, submits the transaction directly without encryption. + decrypt and execute it. If `False`, submits the transaction directly without encryption. period: The number of blocks during which the transaction will remain valid after it's submitted. If the transaction is not included in a block within that number of blocks, it will expire and be rejected. You can think of it as an expiration date for the transaction. - raise_error: Raises a relevant exception rather than returning ``False`` if unsuccessful. - wait_for_inclusion: Whether to wait for the inclusion of the transaction. - wait_for_finalization: Whether to wait for the finalization of the transaction. + raise_error: Raises a relevant exception rather than returning `False` if unsuccessful. + wait_for_inclusion: Waits for the transaction to be included in a block. + wait_for_finalization: Waits for the transaction to be finalized on the blockchain. wait_for_revealed_execution: Whether to wait for the revealed execution of transaction if mev_protection used. Returns: ExtrinsicResponse: The result object of the extrinsic execution. Notes: - - A swap cost is charged when making the first announcement (not when reannouncing). - - After making an announcement, all transactions from the coldkey are blocked except for - `swap_coldkey_announced`. - - The swap can only be executed after the delay period has passed (check via - `get_coldkey_swap_announcement`). - - See: + - Price Protection: + - Rate Limits: """ - return await announce_coldkey_swap_extrinsic( + return await add_stake_multiple_extrinsic( subtensor=self, wallet=wallet, - new_coldkey_ss58=new_coldkey_ss58, + netuids=netuids, + hotkey_ss58s=hotkey_ss58s, + amounts=amounts, mev_protection=mev_protection, period=period, raise_error=raise_error, @@ -6535,12 +6532,14 @@ async def announce_coldkey_swap( wait_for_revealed_execution=wait_for_revealed_execution, ) - async def add_stake_multiple( + async def add_liquidity( self, wallet: "Wallet", - netuids: UIDs, - hotkey_ss58s: list[str], - amounts: list[Balance], + netuid: int, + liquidity: Balance, + price_low: Balance, + price_high: Balance, + hotkey_ss58: Optional[str] = None, *, mev_protection: bool = DEFAULT_MEV_PROTECTION, period: Optional[int] = DEFAULT_PERIOD, @@ -6550,38 +6549,41 @@ async def add_stake_multiple( wait_for_revealed_execution: bool = True, ) -> ExtrinsicResponse: """ - Adds stakes to multiple neurons identified by their hotkey SS58 addresses. - This bulk operation allows for efficient staking across different neurons from a single wallet. + Adds liquidity to the specified price range. Parameters: - wallet: The wallet used for staking. - netuids: List of subnet UIDs. - hotkey_ss58s: List of `SS58` addresses of hotkeys to stake to. - amounts: List of corresponding TAO amounts to bet for each netuid and hotkey. + wallet: The wallet used to sign the extrinsic (must be unlocked). + netuid: The UID of the target subnet for which the call is being initiated. + liquidity: The amount of liquidity to be added. + price_low: The lower bound of the price tick range. In TAO. + price_high: The upper bound of the price tick range. In TAO. + hotkey_ss58: The hotkey with staked TAO in Alpha. If not passed then the wallet hotkey is used. mev_protection: If `True`, encrypts and submits the transaction through the MEV Shield pallet to protect against front-running and MEV attacks. The transaction remains encrypted in the mempool until validators decrypt and execute it. If `False`, submits the transaction directly without encryption. - period: The number of blocks during which the transaction will remain valid after it's submitted. If the - transaction is not included in a block within that number of blocks, it will expire and be rejected. You - can think of it as an expiration date for the transaction. + period: The number of blocks during which the transaction will remain valid after it's submitted. If + the transaction is not included in a block within that number of blocks, it will expire and be rejected. + You can think of it as an expiration date for the transaction. raise_error: Raises a relevant exception rather than returning `False` if unsuccessful. - wait_for_inclusion: Waits for the transaction to be included in a block. - wait_for_finalization: Waits for the transaction to be finalized on the blockchain. + wait_for_inclusion: Whether to wait for the extrinsic to be included in a block. + wait_for_finalization: Whether to wait for finalization of the extrinsic. wait_for_revealed_execution: Whether to wait for the revealed execution of transaction if mev_protection used. Returns: ExtrinsicResponse: The result object of the extrinsic execution. - Notes: - - Price Protection: - - Rate Limits: + Note: + Adding is allowed even when user liquidity is enabled in specified subnet. Call `toggle_user_liquidity` + method to enable/disable user liquidity. """ - return await add_stake_multiple_extrinsic( + return await add_liquidity_extrinsic( subtensor=self, wallet=wallet, - netuids=netuids, - hotkey_ss58s=hotkey_ss58s, - amounts=amounts, + netuid=netuid, + liquidity=liquidity, + price_low=price_low, + price_high=price_high, + hotkey_ss58=hotkey_ss58, mev_protection=mev_protection, period=period, raise_error=raise_error, @@ -6660,6 +6662,62 @@ async def add_proxy( wait_for_revealed_execution=wait_for_revealed_execution, ) + async def announce_coldkey_swap( + self, + wallet: "Wallet", + new_coldkey_ss58: str, + *, + mev_protection: bool = DEFAULT_MEV_PROTECTION, + period: Optional[int] = DEFAULT_PERIOD, + raise_error: bool = False, + wait_for_inclusion: bool = True, + wait_for_finalization: bool = True, + wait_for_revealed_execution: bool = True, + ) -> ExtrinsicResponse: + """ + Announces a coldkey swap by submitting the BlakeTwo256 hash of the new coldkey. + + This method allows a coldkey to declare its intention to swap to a new coldkey address. The announcement must be + made before the actual swap can be executed, and a delay period must pass before execution is allowed. + After making an announcement, all transactions from the coldkey are blocked except for `swap_coldkey_announced`. + + Parameters: + wallet: Bittensor wallet object (should be the current coldkey wallet). + new_coldkey_ss58: SS58 address of the new coldkey that will replace the current one. + mev_protection: If ``True``, encrypts and submits the transaction through the MEV Shield pallet to protect + against front-running and MEV attacks. The transaction remains encrypted in the mempool until validators + decrypt and execute it. If ``False``, submits the transaction directly without encryption. + period: The number of blocks during which the transaction will remain valid after it's submitted. If the + transaction is not included in a block within that number of blocks, it will expire and be rejected. You + can think of it as an expiration date for the transaction. + raise_error: Raises a relevant exception rather than returning ``False`` if unsuccessful. + wait_for_inclusion: Whether to wait for the inclusion of the transaction. + wait_for_finalization: Whether to wait for the finalization of the transaction. + wait_for_revealed_execution: Whether to wait for the revealed execution of transaction if mev_protection used. + + Returns: + ExtrinsicResponse: The result object of the extrinsic execution. + + Notes: + - A swap cost is charged when making the first announcement (not when reannouncing). + - After making an announcement, all transactions from the coldkey are blocked except for + `swap_coldkey_announced`. + - The swap can only be executed after the delay period has passed (check via + `get_coldkey_swap_announcement`). + - See: + """ + return await announce_coldkey_swap_extrinsic( + subtensor=self, + wallet=wallet, + new_coldkey_ss58=new_coldkey_ss58, + mev_protection=mev_protection, + period=period, + raise_error=raise_error, + wait_for_inclusion=wait_for_inclusion, + wait_for_finalization=wait_for_finalization, + wait_for_revealed_execution=wait_for_revealed_execution, + ) + async def announce_proxy( self, wallet: "Wallet", @@ -9126,64 +9184,6 @@ async def start_call( wait_for_revealed_execution=wait_for_revealed_execution, ) - async def subnet_buyback( - self, - wallet: "Wallet", - netuid: int, - hotkey_ss58: str, - amount: Balance, - limit_price: Optional[Balance] = None, - *, - mev_protection: bool = DEFAULT_MEV_PROTECTION, - period: Optional[int] = DEFAULT_PERIOD, - raise_error: bool = False, - wait_for_inclusion: bool = True, - wait_for_finalization: bool = True, - wait_for_revealed_execution: bool = True, - ) -> ExtrinsicResponse: - """ - Executes a subnet buyback by staking TAO and immediately burning the resulting Alpha. - - Only the subnet owner can call this method, and it is rate-limited to one call per subnet tempo. - - Parameters: - wallet: The wallet used to sign the extrinsic (must be the subnet owner). - netuid: The unique identifier of the subnet. - hotkey_ss58: The `SS58` address of the hotkey account to stake to. - amount: The amount of TAO to use for the buyback. - limit_price: Optional limit price expressed in units of RAO per one Alpha. - mev_protection: If `True`, encrypts and submits the transaction through the MEV Shield pallet to protect - against front-running and MEV attacks. The transaction remains encrypted in the mempool until validators - decrypt and execute it. If `False`, submits the transaction directly without encryption. - period: The number of blocks during which the transaction will remain valid after it's submitted. If the - transaction is not included in a block within that number of blocks, it will expire and be rejected. You - can think of it as an expiration date for the transaction. - raise_error: Raises a relevant exception rather than returning `False` if unsuccessful. - wait_for_inclusion: Whether to wait for the inclusion of the transaction. - wait_for_finalization: Whether to wait for the finalization of the transaction. - wait_for_revealed_execution: Whether to wait for the revealed execution of transaction if mev_protection used. - - Returns: - ExtrinsicResponse: The result object of the extrinsic execution. - """ - check_balance_amount(amount) - if limit_price is not None: - check_balance_amount(limit_price) - return await subnet_buyback_extrinsic( - subtensor=self, - wallet=wallet, - netuid=netuid, - hotkey_ss58=hotkey_ss58, - amount=amount, - limit_price=limit_price, - mev_protection=mev_protection, - period=period, - raise_error=raise_error, - wait_for_inclusion=wait_for_inclusion, - wait_for_finalization=wait_for_finalization, - wait_for_revealed_execution=wait_for_revealed_execution, - ) - async def swap_stake( self, wallet: "Wallet", diff --git a/bittensor/core/extrinsics/asyncex/staking.py b/bittensor/core/extrinsics/asyncex/staking.py index c375527882..e23c3ab5d3 100644 --- a/bittensor/core/extrinsics/asyncex/staking.py +++ b/bittensor/core/extrinsics/asyncex/staking.py @@ -18,6 +18,189 @@ from bittensor.core.async_subtensor import AsyncSubtensor +async def add_stake_burn_extrinsic( + subtensor: "AsyncSubtensor", + wallet: "Wallet", + netuid: int, + hotkey_ss58: str, + amount: Balance, + limit_price: Optional[Balance] = None, + *, + mev_protection: bool = DEFAULT_MEV_PROTECTION, + period: Optional[int] = None, + raise_error: bool = False, + wait_for_inclusion: bool = True, + wait_for_finalization: bool = True, + wait_for_revealed_execution: bool = True, +) -> ExtrinsicResponse: + """ + Executes a subnet buyback by staking TAO and immediately burning the resulting Alpha. + + Parameters: + subtensor: Subtensor instance with the connection to the chain. + wallet: Bittensor wallet object. + netuid: The unique identifier of the subnet. + hotkey_ss58: The `ss58` address of the hotkey account to stake to. + amount: Amount to stake as Bittensor balance in TAO always. + limit_price: Optional limit price expressed in units of RAO per one Alpha. + mev_protection: If True, encrypts and submits the transaction through the MEV Shield pallet to protect + against front-running and MEV attacks. The transaction remains encrypted in the mempool until validators + decrypt and execute it. If False, submits the transaction directly without encryption. + period: The number of blocks during which the transaction will remain valid after it's submitted. If the + transaction is not included in a block within that number of blocks, it will expire and be rejected. You can + think of it as an expiration date for the transaction. + raise_error: Raises a relevant exception rather than returning `False` if unsuccessful. + wait_for_inclusion: Whether to wait for the inclusion of the transaction. + wait_for_finalization: Whether to wait for the finalization of the transaction. + wait_for_revealed_execution: Whether to wait for the revealed execution of transaction if mev_protection used. + + Returns: + ExtrinsicResponse: The result object of the extrinsic execution. + + Raises: + SubstrateRequestException: Raised if the extrinsic fails to be included in the block within the timeout. + + Notes: + The `data` field in the returned `ExtrinsicResponse` contains extra information about the extrinsic execution. + """ + try: + if not ( + unlocked := ExtrinsicResponse.unlock_wallet(wallet, raise_error) + ).success: + return unlocked + + if not isinstance(amount, Balance): + raise BalanceTypeError("`amount` must be an instance of Balance.") + + if limit_price is not None and not isinstance(limit_price, Balance): + raise BalanceTypeError("`limit_price` must be an instance of Balance.") + + old_balance = await subtensor.get_balance(wallet.coldkeypub.ss58_address) + block_hash = await subtensor.substrate.get_chain_head() + + # Get current stake and existential deposit + old_stake, existential_deposit = await asyncio.gather( + subtensor.get_stake( + hotkey_ss58=hotkey_ss58, + coldkey_ss58=wallet.coldkeypub.ss58_address, + netuid=netuid, + block_hash=block_hash, + ), + subtensor.get_existential_deposit(block_hash=block_hash), + ) + + # Leave existential balance to keep key alive. + if old_balance <= existential_deposit: + return ExtrinsicResponse( + False, + f"Balance ({old_balance}) is not enough to cover existential deposit `{existential_deposit}`.", + ).with_log() + + # Leave existential balance to keep key alive. + if amount > old_balance - existential_deposit: + # If we are staking all, we need to leave at least the existential deposit. + amount = old_balance - existential_deposit + + # Check enough to stake. + if amount > old_balance: + message = "Not enough stake" + logging.debug(f":cross_mark: [red]{message}:[/red]") + logging.debug(f"\t\tbalance:{old_balance}") + logging.debug(f"\t\tamount: {amount}") + logging.debug(f"\t\twallet: {wallet.name}") + return ExtrinsicResponse(False, f"{message}.").with_log() + + if limit_price is None: + logging.debug( + f"Subnet buyback on: [blue]netuid: [green]{netuid}[/green], amount: [green]{amount}[/green], " + f"hotkey: [green]{hotkey_ss58}[/green] on [blue]{subtensor.network}[/blue]." + ) + else: + logging.debug( + f"Subnet buyback with limit: [blue]netuid: [green]{netuid}[/green], " + f"amount: [green]{amount}[/green], " + f"limit price: [green]{limit_price}[/green], " + f"hotkey: [green]{hotkey_ss58}[/green] on [blue]{subtensor.network}[/blue]." + ) + + call = await SubtensorModule(subtensor).add_stake_burn( + netuid=netuid, + hotkey=hotkey_ss58, + amount=amount.rao, + limit=None if limit_price is None else limit_price.rao, + ) + + block_hash_before = await subtensor.get_block_hash() + if mev_protection: + response = await submit_encrypted_extrinsic( + subtensor=subtensor, + wallet=wallet, + call=call, + period=period, + raise_error=raise_error, + wait_for_inclusion=wait_for_inclusion, + wait_for_finalization=wait_for_finalization, + wait_for_revealed_execution=wait_for_revealed_execution, + ) + else: + response = await subtensor.sign_and_send_extrinsic( + call=call, + wallet=wallet, + wait_for_inclusion=wait_for_inclusion, + wait_for_finalization=wait_for_finalization, + nonce_key="coldkeypub", + use_nonce=True, + period=period, + raise_error=raise_error, + ) + if response.success: + sim_swap = await subtensor.sim_swap( + origin_netuid=0, + destination_netuid=netuid, + amount=amount, + block_hash=block_hash_before, + ) + response.transaction_tao_fee = sim_swap.tao_fee + response.transaction_alpha_fee = sim_swap.alpha_fee.set_unit(netuid) + + if not wait_for_finalization and not wait_for_inclusion: + return response + logging.debug("[green]Finalized.[/green]") + + new_block_hash = await subtensor.substrate.get_chain_head() + new_balance, new_stake = await asyncio.gather( + subtensor.get_balance( + wallet.coldkeypub.ss58_address, block_hash=new_block_hash + ), + subtensor.get_stake( + coldkey_ss58=wallet.coldkeypub.ss58_address, + hotkey_ss58=hotkey_ss58, + netuid=netuid, + block_hash=new_block_hash, + ), + ) + + logging.debug( + f"Balance: [blue]{old_balance}[/blue] :arrow_right: [green]{new_balance}[/green]" + ) + logging.debug( + f"Stake: [blue]{old_stake}[/blue] :arrow_right: [green]{new_stake}[/green]" + ) + response.data = { + "balance_before": old_balance, + "balance_after": new_balance, + "stake_before": old_stake, + "stake_after": new_stake, + } + return response + + logging.error(f"[red]{response.message}[/red]") + return response + + except Exception as error: + return ExtrinsicResponse.from_exception(raise_error=raise_error, error=error) + + async def add_stake_extrinsic( subtensor: "AsyncSubtensor", wallet: "Wallet", @@ -452,189 +635,6 @@ async def add_stake_multiple_extrinsic( return ExtrinsicResponse.from_exception(raise_error=raise_error, error=error) -async def subnet_buyback_extrinsic( - subtensor: "AsyncSubtensor", - wallet: "Wallet", - netuid: int, - hotkey_ss58: str, - amount: Balance, - limit_price: Optional[Balance] = None, - *, - mev_protection: bool = DEFAULT_MEV_PROTECTION, - period: Optional[int] = None, - raise_error: bool = False, - wait_for_inclusion: bool = True, - wait_for_finalization: bool = True, - wait_for_revealed_execution: bool = True, -) -> ExtrinsicResponse: - """ - Executes a subnet buyback by staking TAO and immediately burning the resulting Alpha. - - Parameters: - subtensor: Subtensor instance with the connection to the chain. - wallet: Bittensor wallet object. - netuid: The unique identifier of the subnet. - hotkey_ss58: The `ss58` address of the hotkey account to stake to. - amount: Amount to stake as Bittensor balance in TAO always. - limit_price: Optional limit price expressed in units of RAO per one Alpha. - mev_protection: If True, encrypts and submits the transaction through the MEV Shield pallet to protect - against front-running and MEV attacks. The transaction remains encrypted in the mempool until validators - decrypt and execute it. If False, submits the transaction directly without encryption. - period: The number of blocks during which the transaction will remain valid after it's submitted. If the - transaction is not included in a block within that number of blocks, it will expire and be rejected. You can - think of it as an expiration date for the transaction. - raise_error: Raises a relevant exception rather than returning `False` if unsuccessful. - wait_for_inclusion: Whether to wait for the inclusion of the transaction. - wait_for_finalization: Whether to wait for the finalization of the transaction. - wait_for_revealed_execution: Whether to wait for the revealed execution of transaction if mev_protection used. - - Returns: - ExtrinsicResponse: The result object of the extrinsic execution. - - Raises: - SubstrateRequestException: Raised if the extrinsic fails to be included in the block within the timeout. - - Notes: - The `data` field in the returned `ExtrinsicResponse` contains extra information about the extrinsic execution. - """ - try: - if not ( - unlocked := ExtrinsicResponse.unlock_wallet(wallet, raise_error) - ).success: - return unlocked - - if not isinstance(amount, Balance): - raise BalanceTypeError("`amount` must be an instance of Balance.") - - if limit_price is not None and not isinstance(limit_price, Balance): - raise BalanceTypeError("`limit_price` must be an instance of Balance.") - - old_balance = await subtensor.get_balance(wallet.coldkeypub.ss58_address) - block_hash = await subtensor.substrate.get_chain_head() - - # Get current stake and existential deposit - old_stake, existential_deposit = await asyncio.gather( - subtensor.get_stake( - hotkey_ss58=hotkey_ss58, - coldkey_ss58=wallet.coldkeypub.ss58_address, - netuid=netuid, - block_hash=block_hash, - ), - subtensor.get_existential_deposit(block_hash=block_hash), - ) - - # Leave existential balance to keep key alive. - if old_balance <= existential_deposit: - return ExtrinsicResponse( - False, - f"Balance ({old_balance}) is not enough to cover existential deposit `{existential_deposit}`.", - ).with_log() - - # Leave existential balance to keep key alive. - if amount > old_balance - existential_deposit: - # If we are staking all, we need to leave at least the existential deposit. - amount = old_balance - existential_deposit - - # Check enough to stake. - if amount > old_balance: - message = "Not enough stake" - logging.debug(f":cross_mark: [red]{message}:[/red]") - logging.debug(f"\t\tbalance:{old_balance}") - logging.debug(f"\t\tamount: {amount}") - logging.debug(f"\t\twallet: {wallet.name}") - return ExtrinsicResponse(False, f"{message}.").with_log() - - if limit_price is None: - logging.debug( - f"Subnet buyback on: [blue]netuid: [green]{netuid}[/green], amount: [green]{amount}[/green], " - f"hotkey: [green]{hotkey_ss58}[/green] on [blue]{subtensor.network}[/blue]." - ) - else: - logging.debug( - f"Subnet buyback with limit: [blue]netuid: [green]{netuid}[/green], " - f"amount: [green]{amount}[/green], " - f"limit price: [green]{limit_price}[/green], " - f"hotkey: [green]{hotkey_ss58}[/green] on [blue]{subtensor.network}[/blue]." - ) - - call = await SubtensorModule(subtensor).subnet_buyback( - netuid=netuid, - hotkey=hotkey_ss58, - amount=amount.rao, - limit=None if limit_price is None else limit_price.rao, - ) - - block_hash_before = await subtensor.get_block_hash() - if mev_protection: - response = await submit_encrypted_extrinsic( - subtensor=subtensor, - wallet=wallet, - call=call, - period=period, - raise_error=raise_error, - wait_for_inclusion=wait_for_inclusion, - wait_for_finalization=wait_for_finalization, - wait_for_revealed_execution=wait_for_revealed_execution, - ) - else: - response = await subtensor.sign_and_send_extrinsic( - call=call, - wallet=wallet, - wait_for_inclusion=wait_for_inclusion, - wait_for_finalization=wait_for_finalization, - nonce_key="coldkeypub", - use_nonce=True, - period=period, - raise_error=raise_error, - ) - if response.success: - sim_swap = await subtensor.sim_swap( - origin_netuid=0, - destination_netuid=netuid, - amount=amount, - block_hash=block_hash_before, - ) - response.transaction_tao_fee = sim_swap.tao_fee - response.transaction_alpha_fee = sim_swap.alpha_fee.set_unit(netuid) - - if not wait_for_finalization and not wait_for_inclusion: - return response - logging.debug("[green]Finalized.[/green]") - - new_block_hash = await subtensor.substrate.get_chain_head() - new_balance, new_stake = await asyncio.gather( - subtensor.get_balance( - wallet.coldkeypub.ss58_address, block_hash=new_block_hash - ), - subtensor.get_stake( - coldkey_ss58=wallet.coldkeypub.ss58_address, - hotkey_ss58=hotkey_ss58, - netuid=netuid, - block_hash=new_block_hash, - ), - ) - - logging.debug( - f"Balance: [blue]{old_balance}[/blue] :arrow_right: [green]{new_balance}[/green]" - ) - logging.debug( - f"Stake: [blue]{old_stake}[/blue] :arrow_right: [green]{new_stake}[/green]" - ) - response.data = { - "balance_before": old_balance, - "balance_after": new_balance, - "stake_before": old_stake, - "stake_after": new_stake, - } - return response - - logging.error(f"[red]{response.message}[/red]") - return response - - except Exception as error: - return ExtrinsicResponse.from_exception(raise_error=raise_error, error=error) - - async def set_auto_stake_extrinsic( subtensor: "AsyncSubtensor", wallet: "Wallet", diff --git a/bittensor/core/extrinsics/pallets/subtensor_module.py b/bittensor/core/extrinsics/pallets/subtensor_module.py index 099c5a477d..0da15461cb 100644 --- a/bittensor/core/extrinsics/pallets/subtensor_module.py +++ b/bittensor/core/extrinsics/pallets/subtensor_module.py @@ -49,6 +49,31 @@ def add_stake( amount_staked=amount_staked, ) + def add_stake_burn( + self, + netuid: int, + hotkey: str, + amount: int, + limit: Optional[int] = None, + ) -> Call: + """Returns GenericCall instance for Subtensor function SubtensorModule.add_stake_burn. + + Parameters: + netuid: The netuid of the subnet to buy back on. + hotkey: The hotkey SS58 address associated with the buyback. + amount: Amount of TAO in RAO to use for the buyback. + limit: Optional limit price expressed in units of RAO per one Alpha. + + Returns: + GenericCall instance. + """ + return self.create_composed_call( + netuid=netuid, + hotkey=hotkey, + amount=amount, + limit=limit, + ) + def add_stake_limit( self, netuid: int, @@ -663,31 +688,6 @@ def start_call(self, netuid: int) -> Call: """ return self.create_composed_call(netuid=netuid) - def subnet_buyback( - self, - netuid: int, - hotkey: str, - amount: int, - limit: Optional[int] = None, - ) -> Call: - """Returns GenericCall instance for Subtensor function SubtensorModule.subnet_buyback. - - Parameters: - netuid: The netuid of the subnet to buy back on. - hotkey: The hotkey SS58 address associated with the buyback. - amount: Amount of TAO in RAO to use for the buyback. - limit: Optional limit price expressed in units of RAO per one Alpha. - - Returns: - GenericCall instance. - """ - return self.create_composed_call( - netuid=netuid, - hotkey=hotkey, - amount=amount, - limit=limit, - ) - def swap_stake( self, hotkey: str, diff --git a/bittensor/core/extrinsics/staking.py b/bittensor/core/extrinsics/staking.py index ee28d12055..d84928d95e 100644 --- a/bittensor/core/extrinsics/staking.py +++ b/bittensor/core/extrinsics/staking.py @@ -17,6 +17,185 @@ from bittensor.core.subtensor import Subtensor +def add_stake_burn_extrinsic( + subtensor: "Subtensor", + wallet: "Wallet", + netuid: int, + hotkey_ss58: str, + amount: Balance, + limit_price: Optional[Balance] = None, + *, + mev_protection: bool = DEFAULT_MEV_PROTECTION, + period: Optional[int] = None, + raise_error: bool = False, + wait_for_inclusion: bool = True, + wait_for_finalization: bool = True, + wait_for_revealed_execution: bool = True, +) -> ExtrinsicResponse: + """ + Executes a subnet buyback by staking TAO and immediately burning the resulting Alpha. + + Parameters: + subtensor: Subtensor instance with the connection to the chain. + wallet: Bittensor wallet object. + netuid: The unique identifier of the subnet. + hotkey_ss58: The `ss58` address of the hotkey account to stake to. + amount: Amount to stake as Bittensor balance in TAO always. + limit_price: Optional limit price expressed in units of RAO per one Alpha. + mev_protection: If True, encrypts and submits the transaction through the MEV Shield pallet to protect + against front-running and MEV attacks. The transaction remains encrypted in the mempool until validators + decrypt and execute it. If False, submits the transaction directly without encryption. + period: The number of blocks during which the transaction will remain valid after it's submitted. If the + transaction is not included in a block within that number of blocks, it will expire and be rejected. You can + think of it as an expiration date for the transaction. + raise_error: Raises a relevant exception rather than returning `False` if unsuccessful. + wait_for_inclusion: Whether to wait for the inclusion of the transaction. + wait_for_finalization: Whether to wait for the finalization of the transaction. + wait_for_revealed_execution: Whether to wait for the revealed execution of transaction if mev_protection used. + + Returns: + ExtrinsicResponse: The result object of the extrinsic execution. + + Raises: + SubstrateRequestException: Raised if the extrinsic fails to be included in the block within the timeout. + + Notes: + The `data` field in the returned `ExtrinsicResponse` contains extra information about the extrinsic execution. + """ + try: + if not ( + unlocked := ExtrinsicResponse.unlock_wallet(wallet, raise_error) + ).success: + return unlocked + + if not isinstance(amount, Balance): + raise BalanceTypeError("`amount` must be an instance of Balance.") + + if limit_price is not None and not isinstance(limit_price, Balance): + raise BalanceTypeError("`limit_price` must be an instance of Balance.") + + old_balance = subtensor.get_balance(wallet.coldkeypub.ss58_address) + block = subtensor.get_current_block() + + # Get current stake and existential deposit + old_stake = subtensor.get_stake( + hotkey_ss58=hotkey_ss58, + coldkey_ss58=wallet.coldkeypub.ss58_address, + netuid=netuid, + block=block, + ) + existential_deposit = subtensor.get_existential_deposit(block=block) + + # Leave existential balance to keep key alive. + if old_balance <= existential_deposit: + return ExtrinsicResponse( + False, + f"Balance ({old_balance}) is not enough to cover existential deposit `{existential_deposit}`.", + ).with_log() + + # Leave existential balance to keep key alive. + if amount > old_balance - existential_deposit: + # If we are staking all, we need to leave at least the existential deposit. + amount = old_balance - existential_deposit + + # Check enough to stake. + if amount > old_balance: + message = "Not enough stake" + logging.debug(f":cross_mark: [red]{message}:[/red]") + logging.debug(f"\t\tbalance:{old_balance}") + logging.debug(f"\t\tamount: {amount}") + logging.debug(f"\t\twallet: {wallet.name}") + return ExtrinsicResponse(False, f"{message}.").with_log() + + if limit_price is None: + logging.debug( + f"Subnet buyback on: [blue]netuid: [green]{netuid}[/green], amount: [green]{amount}[/green], " + f"hotkey: [green]{hotkey_ss58}[/green] on [blue]{subtensor.network}[/blue]." + ) + else: + logging.debug( + f"Subnet buyback with limit: [blue]netuid: [green]{netuid}[/green], " + f"amount: [green]{amount}[/green], " + f"limit price: [green]{limit_price}[/green], " + f"hotkey: [green]{hotkey_ss58}[/green] on [blue]{subtensor.network}[/blue]." + ) + + call = SubtensorModule(subtensor).add_stake_burn( + netuid=netuid, + hotkey=hotkey_ss58, + amount=amount.rao, + limit=None if limit_price is None else limit_price.rao, + ) + + block_before = subtensor.block + if mev_protection: + response = submit_encrypted_extrinsic( + subtensor=subtensor, + wallet=wallet, + call=call, + period=period, + raise_error=raise_error, + wait_for_inclusion=wait_for_inclusion, + wait_for_finalization=wait_for_finalization, + wait_for_revealed_execution=wait_for_revealed_execution, + ) + else: + response = subtensor.sign_and_send_extrinsic( + call=call, + wallet=wallet, + wait_for_inclusion=wait_for_inclusion, + wait_for_finalization=wait_for_finalization, + use_nonce=True, + nonce_key="coldkeypub", + period=period, + raise_error=raise_error, + ) + if response.success: + sim_swap = subtensor.sim_swap( + origin_netuid=0, + destination_netuid=netuid, + amount=amount, + block=block_before, + ) + response.transaction_tao_fee = sim_swap.tao_fee + response.transaction_alpha_fee = sim_swap.alpha_fee.set_unit(netuid) + + if not wait_for_finalization and not wait_for_inclusion: + return response + logging.debug("[green]Finalized.[/green]") + + new_block = subtensor.get_current_block() + new_balance = subtensor.get_balance( + wallet.coldkeypub.ss58_address, block=new_block + ) + new_stake = subtensor.get_stake( + coldkey_ss58=wallet.coldkeypub.ss58_address, + hotkey_ss58=hotkey_ss58, + netuid=netuid, + block=new_block, + ) + + logging.debug( + f"Balance: [blue]{old_balance}[/blue] :arrow_right: [green]{new_balance}[/green]" + ) + logging.debug( + f"Stake: [blue]{old_stake}[/blue] :arrow_right: [green]{new_stake}[/green]" + ) + response.data = { + "balance_before": old_balance, + "balance_after": new_balance, + "stake_before": old_stake, + "stake_after": new_stake, + } + return response + + logging.error(f"[red]{response.message}[/red]") + return response + + except Exception as error: + return ExtrinsicResponse.from_exception(raise_error=raise_error, error=error) + + def add_stake_extrinsic( subtensor: "Subtensor", wallet: "Wallet", @@ -443,185 +622,6 @@ def add_stake_multiple_extrinsic( return ExtrinsicResponse.from_exception(raise_error=raise_error, error=error) -def subnet_buyback_extrinsic( - subtensor: "Subtensor", - wallet: "Wallet", - netuid: int, - hotkey_ss58: str, - amount: Balance, - limit_price: Optional[Balance] = None, - *, - mev_protection: bool = DEFAULT_MEV_PROTECTION, - period: Optional[int] = None, - raise_error: bool = False, - wait_for_inclusion: bool = True, - wait_for_finalization: bool = True, - wait_for_revealed_execution: bool = True, -) -> ExtrinsicResponse: - """ - Executes a subnet buyback by staking TAO and immediately burning the resulting Alpha. - - Parameters: - subtensor: Subtensor instance with the connection to the chain. - wallet: Bittensor wallet object. - netuid: The unique identifier of the subnet. - hotkey_ss58: The `ss58` address of the hotkey account to stake to. - amount: Amount to stake as Bittensor balance in TAO always. - limit_price: Optional limit price expressed in units of RAO per one Alpha. - mev_protection: If True, encrypts and submits the transaction through the MEV Shield pallet to protect - against front-running and MEV attacks. The transaction remains encrypted in the mempool until validators - decrypt and execute it. If False, submits the transaction directly without encryption. - period: The number of blocks during which the transaction will remain valid after it's submitted. If the - transaction is not included in a block within that number of blocks, it will expire and be rejected. You can - think of it as an expiration date for the transaction. - raise_error: Raises a relevant exception rather than returning `False` if unsuccessful. - wait_for_inclusion: Whether to wait for the inclusion of the transaction. - wait_for_finalization: Whether to wait for the finalization of the transaction. - wait_for_revealed_execution: Whether to wait for the revealed execution of transaction if mev_protection used. - - Returns: - ExtrinsicResponse: The result object of the extrinsic execution. - - Raises: - SubstrateRequestException: Raised if the extrinsic fails to be included in the block within the timeout. - - Notes: - The `data` field in the returned `ExtrinsicResponse` contains extra information about the extrinsic execution. - """ - try: - if not ( - unlocked := ExtrinsicResponse.unlock_wallet(wallet, raise_error) - ).success: - return unlocked - - if not isinstance(amount, Balance): - raise BalanceTypeError("`amount` must be an instance of Balance.") - - if limit_price is not None and not isinstance(limit_price, Balance): - raise BalanceTypeError("`limit_price` must be an instance of Balance.") - - old_balance = subtensor.get_balance(wallet.coldkeypub.ss58_address) - block = subtensor.get_current_block() - - # Get current stake and existential deposit - old_stake = subtensor.get_stake( - hotkey_ss58=hotkey_ss58, - coldkey_ss58=wallet.coldkeypub.ss58_address, - netuid=netuid, - block=block, - ) - existential_deposit = subtensor.get_existential_deposit(block=block) - - # Leave existential balance to keep key alive. - if old_balance <= existential_deposit: - return ExtrinsicResponse( - False, - f"Balance ({old_balance}) is not enough to cover existential deposit `{existential_deposit}`.", - ).with_log() - - # Leave existential balance to keep key alive. - if amount > old_balance - existential_deposit: - # If we are staking all, we need to leave at least the existential deposit. - amount = old_balance - existential_deposit - - # Check enough to stake. - if amount > old_balance: - message = "Not enough stake" - logging.debug(f":cross_mark: [red]{message}:[/red]") - logging.debug(f"\t\tbalance:{old_balance}") - logging.debug(f"\t\tamount: {amount}") - logging.debug(f"\t\twallet: {wallet.name}") - return ExtrinsicResponse(False, f"{message}.").with_log() - - if limit_price is None: - logging.debug( - f"Subnet buyback on: [blue]netuid: [green]{netuid}[/green], amount: [green]{amount}[/green], " - f"hotkey: [green]{hotkey_ss58}[/green] on [blue]{subtensor.network}[/blue]." - ) - else: - logging.debug( - f"Subnet buyback with limit: [blue]netuid: [green]{netuid}[/green], " - f"amount: [green]{amount}[/green], " - f"limit price: [green]{limit_price}[/green], " - f"hotkey: [green]{hotkey_ss58}[/green] on [blue]{subtensor.network}[/blue]." - ) - - call = SubtensorModule(subtensor).subnet_buyback( - netuid=netuid, - hotkey=hotkey_ss58, - amount=amount.rao, - limit=None if limit_price is None else limit_price.rao, - ) - - block_before = subtensor.block - if mev_protection: - response = submit_encrypted_extrinsic( - subtensor=subtensor, - wallet=wallet, - call=call, - period=period, - raise_error=raise_error, - wait_for_inclusion=wait_for_inclusion, - wait_for_finalization=wait_for_finalization, - wait_for_revealed_execution=wait_for_revealed_execution, - ) - else: - response = subtensor.sign_and_send_extrinsic( - call=call, - wallet=wallet, - wait_for_inclusion=wait_for_inclusion, - wait_for_finalization=wait_for_finalization, - use_nonce=True, - nonce_key="coldkeypub", - period=period, - raise_error=raise_error, - ) - if response.success: - sim_swap = subtensor.sim_swap( - origin_netuid=0, - destination_netuid=netuid, - amount=amount, - block=block_before, - ) - response.transaction_tao_fee = sim_swap.tao_fee - response.transaction_alpha_fee = sim_swap.alpha_fee.set_unit(netuid) - - if not wait_for_finalization and not wait_for_inclusion: - return response - logging.debug("[green]Finalized.[/green]") - - new_block = subtensor.get_current_block() - new_balance = subtensor.get_balance( - wallet.coldkeypub.ss58_address, block=new_block - ) - new_stake = subtensor.get_stake( - coldkey_ss58=wallet.coldkeypub.ss58_address, - hotkey_ss58=hotkey_ss58, - netuid=netuid, - block=new_block, - ) - - logging.debug( - f"Balance: [blue]{old_balance}[/blue] :arrow_right: [green]{new_balance}[/green]" - ) - logging.debug( - f"Stake: [blue]{old_stake}[/blue] :arrow_right: [green]{new_stake}[/green]" - ) - response.data = { - "balance_before": old_balance, - "balance_after": new_balance, - "stake_before": old_stake, - "stake_after": new_stake, - } - return response - - logging.error(f"[red]{response.message}[/red]") - return response - - except Exception as error: - return ExtrinsicResponse.from_exception(raise_error=raise_error, error=error) - - def set_auto_stake_extrinsic( subtensor: "Subtensor", wallet: "Wallet", diff --git a/bittensor/core/subtensor.py b/bittensor/core/subtensor.py index 2181046d71..9ad9c1fb6c 100644 --- a/bittensor/core/subtensor.py +++ b/bittensor/core/subtensor.py @@ -110,10 +110,10 @@ serve_axon_extrinsic, ) from bittensor.core.extrinsics.staking import ( + add_stake_burn_extrinsic, add_stake_extrinsic, add_stake_multiple_extrinsic, set_auto_stake_extrinsic, - subnet_buyback_extrinsic, ) from bittensor.core.extrinsics.start_call import start_call_extrinsic from bittensor.core.extrinsics.take import set_take_extrinsic @@ -5225,14 +5225,13 @@ def add_stake( wait_for_revealed_execution=wait_for_revealed_execution, ) - def add_liquidity( + def add_stake_burn( self, wallet: "Wallet", netuid: int, - liquidity: Balance, - price_low: Balance, - price_high: Balance, - hotkey_ss58: Optional[str] = None, + hotkey_ss58: str, + amount: Balance, + limit_price: Optional[Balance] = None, *, mev_protection: bool = DEFAULT_MEV_PROTECTION, period: Optional[int] = DEFAULT_PERIOD, @@ -5242,40 +5241,40 @@ def add_liquidity( wait_for_revealed_execution: bool = True, ) -> ExtrinsicResponse: """ - Adds liquidity to the specified price range. + Executes a subnet buyback by staking TAO and immediately burning the resulting Alpha. + + Only the subnet owner can call this method, and it is rate-limited to one call per subnet tempo. Parameters: - wallet: The wallet used to sign the extrinsic (must be unlocked). - netuid: The UID of the target subnet for which the call is being initiated. - liquidity: The amount of liquidity to be added. - price_low: The lower bound of the price tick range. In TAO. - price_high: The upper bound of the price tick range. In TAO. - hotkey_ss58: The hotkey with staked TAO in Alpha. If not passed then the wallet hotkey is used. + wallet: The wallet used to sign the extrinsic (must be the subnet owner). + netuid: The unique identifier of the subnet. + hotkey_ss58: The `SS58` address of the hotkey account to stake to. + amount: The amount of TAO to use for the buyback. + limit_price: Optional limit price expressed in units of RAO per one Alpha. mev_protection: If `True`, encrypts and submits the transaction through the MEV Shield pallet to protect against front-running and MEV attacks. The transaction remains encrypted in the mempool until validators decrypt and execute it. If `False`, submits the transaction directly without encryption. - period: The number of blocks during which the transaction will remain valid after it's submitted. If - the transaction is not included in a block within that number of blocks, it will expire and be rejected. - You can think of it as an expiration date for the transaction. + period: The number of blocks during which the transaction will remain valid after it's submitted. If the + transaction is not included in a block within that number of blocks, it will expire and be rejected. You + can think of it as an expiration date for the transaction. raise_error: Raises a relevant exception rather than returning `False` if unsuccessful. - wait_for_inclusion: Whether to wait for the extrinsic to be included in a block. - wait_for_finalization: Whether to wait for finalization of the extrinsic. + wait_for_inclusion: Whether to wait for the inclusion of the transaction. + wait_for_finalization: Whether to wait for the finalization of the transaction. wait_for_revealed_execution: Whether to wait for the revealed execution of transaction if mev_protection used. Returns: ExtrinsicResponse: The result object of the extrinsic execution. - - Note: Adding is allowed even when user liquidity is enabled in specified subnet. Call `toggle_user_liquidity` - method to enable/disable user liquidity. """ - return add_liquidity_extrinsic( + check_balance_amount(amount) + if limit_price is not None: + check_balance_amount(limit_price) + return add_stake_burn_extrinsic( subtensor=self, wallet=wallet, netuid=netuid, - liquidity=liquidity, - price_low=price_low, - price_high=price_high, hotkey_ss58=hotkey_ss58, + amount=amount, + limit_price=limit_price, mev_protection=mev_protection, period=period, raise_error=raise_error, @@ -5284,10 +5283,12 @@ def add_liquidity( wait_for_revealed_execution=wait_for_revealed_execution, ) - def announce_coldkey_swap( + def add_stake_multiple( self, wallet: "Wallet", - new_coldkey_ss58: str, + netuids: UIDs, + hotkey_ss58s: list[str], + amounts: list[Balance], *, mev_protection: bool = DEFAULT_MEV_PROTECTION, period: Optional[int] = DEFAULT_PERIOD, @@ -5297,15 +5298,14 @@ def announce_coldkey_swap( wait_for_revealed_execution: bool = True, ) -> ExtrinsicResponse: """ - Announces a coldkey swap by submitting the BlakeTwo256 hash of the new coldkey. - - This method allows a coldkey to declare its intention to swap to a new coldkey address. The announcement must be - made before the actual swap can be executed, and a delay period must pass before execution is allowed. - After making an announcement, all transactions from the coldkey are blocked except for `swap_coldkey_announced`. + Adds stakes to multiple neurons identified by their hotkey SS58 addresses. + This bulk operation allows for efficient staking across different neurons from a single wallet. Parameters: - wallet: Bittensor wallet object (should be the current coldkey wallet). - new_coldkey_ss58: SS58 address of the new coldkey that will replace the current one. + wallet: The wallet used for staking. + netuids: List of subnet UIDs. + hotkey_ss58s: List of `SS58` addresses of hotkeys to stake to. + amounts: List of corresponding TAO amounts to bet for each netuid and hotkey. mev_protection: If `True`, encrypts and submits the transaction through the MEV Shield pallet to protect against front-running and MEV attacks. The transaction remains encrypted in the mempool until validators decrypt and execute it. If `False`, submits the transaction directly without encryption. @@ -5313,25 +5313,23 @@ def announce_coldkey_swap( transaction is not included in a block within that number of blocks, it will expire and be rejected. You can think of it as an expiration date for the transaction. raise_error: Raises a relevant exception rather than returning `False` if unsuccessful. - wait_for_inclusion: Whether to wait for the inclusion of the transaction. - wait_for_finalization: Whether to wait for the finalization of the transaction. + wait_for_inclusion: Waits for the transaction to be included in a block. + wait_for_finalization: Waits for the transaction to be finalized on the blockchain. wait_for_revealed_execution: Whether to wait for the revealed execution of transaction if mev_protection used. Returns: ExtrinsicResponse: The result object of the extrinsic execution. Notes: - - A swap cost is charged when making the first announcement (not when reannouncing). - - After making an announcement, all transactions from the coldkey are blocked except for ` - swap_coldkey_announced`. - - The swap can only be executed after the delay period has passed (check via - `get_coldkey_swap_announcement`). - - See: + - Price Protection: + - Rate Limits: """ - return announce_coldkey_swap_extrinsic( + return add_stake_multiple_extrinsic( subtensor=self, wallet=wallet, - new_coldkey_ss58=new_coldkey_ss58, + netuids=netuids, + hotkey_ss58s=hotkey_ss58s, + amounts=amounts, mev_protection=mev_protection, period=period, raise_error=raise_error, @@ -5340,12 +5338,14 @@ def announce_coldkey_swap( wait_for_revealed_execution=wait_for_revealed_execution, ) - def add_stake_multiple( + def add_liquidity( self, wallet: "Wallet", - netuids: UIDs, - hotkey_ss58s: list[str], - amounts: list[Balance], + netuid: int, + liquidity: Balance, + price_low: Balance, + price_high: Balance, + hotkey_ss58: Optional[str] = None, *, mev_protection: bool = DEFAULT_MEV_PROTECTION, period: Optional[int] = DEFAULT_PERIOD, @@ -5355,38 +5355,40 @@ def add_stake_multiple( wait_for_revealed_execution: bool = True, ) -> ExtrinsicResponse: """ - Adds stakes to multiple neurons identified by their hotkey SS58 addresses. - This bulk operation allows for efficient staking across different neurons from a single wallet. + Adds liquidity to the specified price range. Parameters: - wallet: The wallet used for staking. - netuids: List of subnet UIDs. - hotkey_ss58s: List of `SS58` addresses of hotkeys to stake to. - amounts: List of corresponding TAO amounts to bet for each netuid and hotkey. + wallet: The wallet used to sign the extrinsic (must be unlocked). + netuid: The UID of the target subnet for which the call is being initiated. + liquidity: The amount of liquidity to be added. + price_low: The lower bound of the price tick range. In TAO. + price_high: The upper bound of the price tick range. In TAO. + hotkey_ss58: The hotkey with staked TAO in Alpha. If not passed then the wallet hotkey is used. mev_protection: If `True`, encrypts and submits the transaction through the MEV Shield pallet to protect against front-running and MEV attacks. The transaction remains encrypted in the mempool until validators decrypt and execute it. If `False`, submits the transaction directly without encryption. - period: The number of blocks during which the transaction will remain valid after it's submitted. If the - transaction is not included in a block within that number of blocks, it will expire and be rejected. You - can think of it as an expiration date for the transaction. + period: The number of blocks during which the transaction will remain valid after it's submitted. If + the transaction is not included in a block within that number of blocks, it will expire and be rejected. + You can think of it as an expiration date for the transaction. raise_error: Raises a relevant exception rather than returning `False` if unsuccessful. - wait_for_inclusion: Waits for the transaction to be included in a block. - wait_for_finalization: Waits for the transaction to be finalized on the blockchain. + wait_for_inclusion: Whether to wait for the extrinsic to be included in a block. + wait_for_finalization: Whether to wait for finalization of the extrinsic. wait_for_revealed_execution: Whether to wait for the revealed execution of transaction if mev_protection used. Returns: ExtrinsicResponse: The result object of the extrinsic execution. - Notes: - - Price Protection: - - Rate Limits: + Note: Adding is allowed even when user liquidity is enabled in specified subnet. Call `toggle_user_liquidity` + method to enable/disable user liquidity. """ - return add_stake_multiple_extrinsic( + return add_liquidity_extrinsic( subtensor=self, wallet=wallet, - netuids=netuids, - hotkey_ss58s=hotkey_ss58s, - amounts=amounts, + netuid=netuid, + liquidity=liquidity, + price_low=price_low, + price_high=price_high, + hotkey_ss58=hotkey_ss58, mev_protection=mev_protection, period=period, raise_error=raise_error, @@ -5455,6 +5457,62 @@ def add_proxy( wait_for_revealed_execution=wait_for_revealed_execution, ) + def announce_coldkey_swap( + self, + wallet: "Wallet", + new_coldkey_ss58: str, + *, + mev_protection: bool = DEFAULT_MEV_PROTECTION, + period: Optional[int] = DEFAULT_PERIOD, + raise_error: bool = False, + wait_for_inclusion: bool = True, + wait_for_finalization: bool = True, + wait_for_revealed_execution: bool = True, + ) -> ExtrinsicResponse: + """ + Announces a coldkey swap by submitting the BlakeTwo256 hash of the new coldkey. + + This method allows a coldkey to declare its intention to swap to a new coldkey address. The announcement must be + made before the actual swap can be executed, and a delay period must pass before execution is allowed. + After making an announcement, all transactions from the coldkey are blocked except for `swap_coldkey_announced`. + + Parameters: + wallet: Bittensor wallet object (should be the current coldkey wallet). + new_coldkey_ss58: SS58 address of the new coldkey that will replace the current one. + mev_protection: If `True`, encrypts and submits the transaction through the MEV Shield pallet to protect + against front-running and MEV attacks. The transaction remains encrypted in the mempool until validators + decrypt and execute it. If `False`, submits the transaction directly without encryption. + period: The number of blocks during which the transaction will remain valid after it's submitted. If the + transaction is not included in a block within that number of blocks, it will expire and be rejected. You + can think of it as an expiration date for the transaction. + raise_error: Raises a relevant exception rather than returning `False` if unsuccessful. + wait_for_inclusion: Whether to wait for the inclusion of the transaction. + wait_for_finalization: Whether to wait for the finalization of the transaction. + wait_for_revealed_execution: Whether to wait for the revealed execution of transaction if mev_protection used. + + Returns: + ExtrinsicResponse: The result object of the extrinsic execution. + + Notes: + - A swap cost is charged when making the first announcement (not when reannouncing). + - After making an announcement, all transactions from the coldkey are blocked except for ` + swap_coldkey_announced`. + - The swap can only be executed after the delay period has passed (check via + `get_coldkey_swap_announcement`). + - See: + """ + return announce_coldkey_swap_extrinsic( + subtensor=self, + wallet=wallet, + new_coldkey_ss58=new_coldkey_ss58, + mev_protection=mev_protection, + period=period, + raise_error=raise_error, + wait_for_inclusion=wait_for_inclusion, + wait_for_finalization=wait_for_finalization, + wait_for_revealed_execution=wait_for_revealed_execution, + ) + def announce_proxy( self, wallet: "Wallet", @@ -7834,64 +7892,6 @@ def start_call( wait_for_revealed_execution=wait_for_revealed_execution, ) - def subnet_buyback( - self, - wallet: "Wallet", - netuid: int, - hotkey_ss58: str, - amount: Balance, - limit_price: Optional[Balance] = None, - *, - mev_protection: bool = DEFAULT_MEV_PROTECTION, - period: Optional[int] = DEFAULT_PERIOD, - raise_error: bool = False, - wait_for_inclusion: bool = True, - wait_for_finalization: bool = True, - wait_for_revealed_execution: bool = True, - ) -> ExtrinsicResponse: - """ - Executes a subnet buyback by staking TAO and immediately burning the resulting Alpha. - - Only the subnet owner can call this method, and it is rate-limited to one call per subnet tempo. - - Parameters: - wallet: The wallet used to sign the extrinsic (must be the subnet owner). - netuid: The unique identifier of the subnet. - hotkey_ss58: The `SS58` address of the hotkey account to stake to. - amount: The amount of TAO to use for the buyback. - limit_price: Optional limit price expressed in units of RAO per one Alpha. - mev_protection: If `True`, encrypts and submits the transaction through the MEV Shield pallet to protect - against front-running and MEV attacks. The transaction remains encrypted in the mempool until validators - decrypt and execute it. If `False`, submits the transaction directly without encryption. - period: The number of blocks during which the transaction will remain valid after it's submitted. If the - transaction is not included in a block within that number of blocks, it will expire and be rejected. You - can think of it as an expiration date for the transaction. - raise_error: Raises a relevant exception rather than returning `False` if unsuccessful. - wait_for_inclusion: Whether to wait for the inclusion of the transaction. - wait_for_finalization: Whether to wait for the finalization of the transaction. - wait_for_revealed_execution: Whether to wait for the revealed execution of transaction if mev_protection used. - - Returns: - ExtrinsicResponse: The result object of the extrinsic execution. - """ - check_balance_amount(amount) - if limit_price is not None: - check_balance_amount(limit_price) - return subnet_buyback_extrinsic( - subtensor=self, - wallet=wallet, - netuid=netuid, - hotkey_ss58=hotkey_ss58, - amount=amount, - limit_price=limit_price, - mev_protection=mev_protection, - period=period, - raise_error=raise_error, - wait_for_inclusion=wait_for_inclusion, - wait_for_finalization=wait_for_finalization, - wait_for_revealed_execution=wait_for_revealed_execution, - ) - def swap_stake( self, wallet: "Wallet", diff --git a/bittensor/extras/dev_framework/calls/non_sudo_calls.py b/bittensor/extras/dev_framework/calls/non_sudo_calls.py index 04c898524f..62fb1166f0 100644 --- a/bittensor/extras/dev_framework/calls/non_sudo_calls.py +++ b/bittensor/extras/dev_framework/calls/non_sudo_calls.py @@ -11,7 +11,7 @@ Note: Any manual changes will be overwritten the next time the generator is run. - Subtensor spec version: 375 + Subtensor spec version: 376 """ from collections import namedtuple @@ -27,6 +27,9 @@ ADD_STAKE = namedtuple( "ADD_STAKE", ["wallet", "pallet", "hotkey", "netuid", "amount_staked"] ) # args: [hotkey: T::AccountId, netuid: NetUid, amount_staked: TaoCurrency] | Pallet: SubtensorModule +ADD_STAKE_BURN = namedtuple( + "ADD_STAKE_BURN", ["wallet", "pallet", "hotkey", "netuid", "amount", "limit"] +) # args: [hotkey: T::AccountId, netuid: NetUid, amount: TaoCurrency, limit: Option] | Pallet: SubtensorModule ADD_STAKE_LIMIT = namedtuple( "ADD_STAKE_LIMIT", [ @@ -745,9 +748,6 @@ SUBMIT_ENCRYPTED = namedtuple( "SUBMIT_ENCRYPTED", ["wallet", "pallet", "commitment", "ciphertext"] ) # args: [commitment: T::Hash, ciphertext: BoundedVec>] | Pallet: MevShield -SUBNET_BUYBACK = namedtuple( - "SUBNET_BUYBACK", ["wallet", "pallet", "hotkey", "netuid", "amount", "limit"] -) # args: [hotkey: T::AccountId, netuid: NetUid, amount: TaoCurrency, limit: Option] | Pallet: SubtensorModule SUDO = namedtuple( "SUDO", ["wallet", "pallet", "call"] ) # args: [call: Box<::RuntimeCall>] | Pallet: Sudo diff --git a/bittensor/extras/dev_framework/calls/pallets.py b/bittensor/extras/dev_framework/calls/pallets.py index abba174a69..72f0dc092f 100644 --- a/bittensor/extras/dev_framework/calls/pallets.py +++ b/bittensor/extras/dev_framework/calls/pallets.py @@ -1,5 +1,5 @@ """ " -Subtensor spec version: 375 +Subtensor spec version: 376 """ System = "System" diff --git a/bittensor/extras/dev_framework/calls/sudo_calls.py b/bittensor/extras/dev_framework/calls/sudo_calls.py index 452eb60940..7b29a05d99 100644 --- a/bittensor/extras/dev_framework/calls/sudo_calls.py +++ b/bittensor/extras/dev_framework/calls/sudo_calls.py @@ -11,7 +11,7 @@ Note: Any manual changes will be overwritten the next time the generator is run. - Subtensor spec version: 375 + Subtensor spec version: 376 """ from collections import namedtuple diff --git a/bittensor/extras/subtensor_api/extrinsics.py b/bittensor/extras/subtensor_api/extrinsics.py index b1bb000336..43fafc79ad 100644 --- a/bittensor/extras/subtensor_api/extrinsics.py +++ b/bittensor/extras/subtensor_api/extrinsics.py @@ -10,6 +10,7 @@ class Extrinsics: def __init__(self, subtensor: Union["_Subtensor", "_AsyncSubtensor"]): self.add_liquidity = subtensor.add_liquidity self.add_stake = subtensor.add_stake + self.add_stake_burn = subtensor.add_stake_burn self.add_stake_multiple = subtensor.add_stake_multiple self.announce_coldkey_swap = subtensor.announce_coldkey_swap self.dispute_coldkey_swap = subtensor.dispute_coldkey_swap @@ -39,7 +40,6 @@ def __init__(self, subtensor: Union["_Subtensor", "_AsyncSubtensor"]): self.set_commitment = subtensor.set_commitment self.set_root_claim_type = subtensor.set_root_claim_type self.start_call = subtensor.start_call - self.subnet_buyback = subtensor.subnet_buyback self.swap_coldkey_announced = subtensor.swap_coldkey_announced self.swap_stake = subtensor.swap_stake self.toggle_user_liquidity = subtensor.toggle_user_liquidity diff --git a/bittensor/extras/subtensor_api/staking.py b/bittensor/extras/subtensor_api/staking.py index 7bc26f1f6f..0ab2e5485b 100644 --- a/bittensor/extras/subtensor_api/staking.py +++ b/bittensor/extras/subtensor_api/staking.py @@ -8,6 +8,7 @@ class Staking: def __init__(self, subtensor: Union["_Subtensor", "_AsyncSubtensor"]): self.add_stake = subtensor.add_stake + self.add_stake_burn = subtensor.add_stake_burn self.add_stake_multiple = subtensor.add_stake_multiple self.claim_root = subtensor.claim_root self.get_auto_stakes = subtensor.get_auto_stakes @@ -35,7 +36,6 @@ def __init__(self, subtensor: Union["_Subtensor", "_AsyncSubtensor"]): self.set_auto_stake = subtensor.set_auto_stake self.set_root_claim_type = subtensor.set_root_claim_type self.sim_swap = subtensor.sim_swap - self.subnet_buyback = subtensor.subnet_buyback self.swap_stake = subtensor.swap_stake self.transfer_stake = subtensor.transfer_stake self.unstake = subtensor.unstake diff --git a/tests/e2e_tests/test_subnet_buyback.py b/tests/e2e_tests/test_add_stake_burn.py similarity index 93% rename from tests/e2e_tests/test_subnet_buyback.py rename to tests/e2e_tests/test_add_stake_burn.py index 6ef853a864..3fc329236f 100644 --- a/tests/e2e_tests/test_subnet_buyback.py +++ b/tests/e2e_tests/test_add_stake_burn.py @@ -9,7 +9,7 @@ ) -def test_subnet_buyback(subtensor, alice_wallet, bob_wallet): +def test_add_stake_burn(subtensor, alice_wallet, bob_wallet): """Tests subnet buyback without limit price. Steps: @@ -39,7 +39,7 @@ def test_subnet_buyback(subtensor, alice_wallet, bob_wallet): address=alice_wallet.coldkeypub.ss58_address ) - response = subtensor.staking.subnet_buyback( + response = subtensor.staking.add_stake_burn( wallet=alice_wallet, netuid=alice_sn.netuid, hotkey_ss58=bob_wallet.hotkey.ss58_address, @@ -64,7 +64,7 @@ def test_subnet_buyback(subtensor, alice_wallet, bob_wallet): @pytest.mark.asyncio -async def test_subnet_buyback_async(async_subtensor, alice_wallet, bob_wallet): +async def test_add_stake_burn_async(async_subtensor, alice_wallet, bob_wallet): """Tests subnet buyback without limit price (async). Steps: @@ -94,7 +94,7 @@ async def test_subnet_buyback_async(async_subtensor, alice_wallet, bob_wallet): address=alice_wallet.coldkeypub.ss58_address ) - response = await async_subtensor.staking.subnet_buyback( + response = await async_subtensor.staking.add_stake_burn( wallet=alice_wallet, netuid=alice_sn.netuid, hotkey_ss58=bob_wallet.hotkey.ss58_address, @@ -118,7 +118,7 @@ async def test_subnet_buyback_async(async_subtensor, alice_wallet, bob_wallet): assert balance_after < balance_before -def test_subnet_buyback_with_limit_price(subtensor, alice_wallet, bob_wallet): +def test_add_stake_burn_with_limit_price(subtensor, alice_wallet, bob_wallet): """Tests subnet buyback with limit price. Steps: @@ -148,7 +148,7 @@ def test_subnet_buyback_with_limit_price(subtensor, alice_wallet, bob_wallet): address=alice_wallet.coldkeypub.ss58_address ) - response = subtensor.staking.subnet_buyback( + response = subtensor.staking.add_stake_burn( wallet=alice_wallet, netuid=alice_sn.netuid, hotkey_ss58=bob_wallet.hotkey.ss58_address, @@ -174,7 +174,7 @@ def test_subnet_buyback_with_limit_price(subtensor, alice_wallet, bob_wallet): @pytest.mark.asyncio -async def test_subnet_buyback_with_limit_price_async( +async def test_add_stake_burn_with_limit_price_async( async_subtensor, alice_wallet, bob_wallet ): """Tests subnet buyback with limit price (async). @@ -206,7 +206,7 @@ async def test_subnet_buyback_with_limit_price_async( address=alice_wallet.coldkeypub.ss58_address ) - response = await async_subtensor.staking.subnet_buyback( + response = await async_subtensor.staking.add_stake_burn( wallet=alice_wallet, netuid=alice_sn.netuid, hotkey_ss58=bob_wallet.hotkey.ss58_address, diff --git a/tests/unit_tests/extrinsics/asyncex/test_staking.py b/tests/unit_tests/extrinsics/asyncex/test_staking.py index 2126ad3680..a68e8a6362 100644 --- a/tests/unit_tests/extrinsics/asyncex/test_staking.py +++ b/tests/unit_tests/extrinsics/asyncex/test_staking.py @@ -79,14 +79,14 @@ async def test_subnet_buyback_extrinsic(fake_wallet, mocker): mocked_pallet_compose_call = mocker.AsyncMock() mocker.patch.object( - staking.SubtensorModule, "subnet_buyback", new=mocked_pallet_compose_call + staking.SubtensorModule, "add_stake_burn", new=mocked_pallet_compose_call ) fake_subtensor.sim_swap = mocker.AsyncMock( return_value=mocker.Mock(tao_fee=Balance.from_rao(1), alpha_fee=mocker.Mock()) ) # Call - result = await staking.subnet_buyback_extrinsic( + result = await staking.add_stake_burn_extrinsic( subtensor=fake_subtensor, wallet=fake_wallet, hotkey_ss58=hotkey_ss58, @@ -141,14 +141,14 @@ async def test_subnet_buyback_extrinsic_with_limit(fake_wallet, mocker): mocked_pallet_compose_call = mocker.AsyncMock() mocker.patch.object( - staking.SubtensorModule, "subnet_buyback", new=mocked_pallet_compose_call + staking.SubtensorModule, "add_stake_burn", new=mocked_pallet_compose_call ) fake_subtensor.sim_swap = mocker.AsyncMock( return_value=mocker.Mock(tao_fee=Balance.from_rao(1), alpha_fee=mocker.Mock()) ) # Call - result = await staking.subnet_buyback_extrinsic( + result = await staking.add_stake_burn_extrinsic( subtensor=fake_subtensor, wallet=fake_wallet, hotkey_ss58=hotkey_ss58, diff --git a/tests/unit_tests/extrinsics/test_staking.py b/tests/unit_tests/extrinsics/test_staking.py index b559e0e381..c354daf0db 100644 --- a/tests/unit_tests/extrinsics/test_staking.py +++ b/tests/unit_tests/extrinsics/test_staking.py @@ -65,8 +65,8 @@ def test_add_stake_extrinsic(mocker): ) -def test_subnet_buyback_extrinsic(mocker): - """Verify that sync `subnet_buyback_extrinsic` method calls proper methods.""" +def test_add_stake_burn_extrinsic(mocker): + """Verify that sync `add_stake_burn_extrinsic` method calls proper methods.""" # Preps fake_subtensor = mocker.Mock( **{ @@ -87,7 +87,7 @@ def test_subnet_buyback_extrinsic(mocker): amount = Balance.from_tao(2) # Call - result = staking.subnet_buyback_extrinsic( + result = staking.add_stake_burn_extrinsic( subtensor=fake_subtensor, wallet=fake_wallet, hotkey_ss58=hotkey_ss58, @@ -103,7 +103,7 @@ def test_subnet_buyback_extrinsic(mocker): assert result.success is True fake_subtensor.compose_call.assert_called_once_with( call_module="SubtensorModule", - call_function="subnet_buyback", + call_function="add_stake_burn", call_params={ "hotkey": hotkey_ss58, "netuid": netuid, @@ -123,8 +123,8 @@ def test_subnet_buyback_extrinsic(mocker): ) -def test_subnet_buyback_extrinsic_with_limit(mocker): - """Verify that sync `subnet_buyback_extrinsic` passes limit price.""" +def test_add_stake_burn_extrinsic_with_limit(mocker): + """Verify that sync `add_stake_burn_extrinsic` passes limit price.""" # Preps fake_subtensor = mocker.Mock( **{ @@ -146,7 +146,7 @@ def test_subnet_buyback_extrinsic_with_limit(mocker): limit_price = Balance.from_tao(2) # Call - result = staking.subnet_buyback_extrinsic( + result = staking.add_stake_burn_extrinsic( subtensor=fake_subtensor, wallet=fake_wallet, hotkey_ss58=hotkey_ss58, @@ -163,7 +163,7 @@ def test_subnet_buyback_extrinsic_with_limit(mocker): assert result.success is True fake_subtensor.compose_call.assert_called_once_with( call_module="SubtensorModule", - call_function="subnet_buyback", + call_function="add_stake_burn", call_params={ "hotkey": hotkey_ss58, "netuid": netuid, @@ -181,9 +181,7 @@ def test_add_stake_multiple_extrinsic(subtensor, mocker, fake_wallet): "get_stake_info_for_coldkey", return_value=[Balance(1.1), Balance(0.3)], ) - mocked_get_balance = mocker.patch.object( - subtensor, "get_balance", return_value=Balance.from_tao(10) - ) + mocker.patch.object(subtensor, "get_balance", return_value=Balance.from_tao(10)) mocker.patch.object( staking, "get_old_stakes", return_value=[Balance(1.1), Balance(0.3)] ) diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index ae657c55e3..f77067054d 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -2921,17 +2921,17 @@ async def test_start_call(subtensor, mocker): @pytest.mark.asyncio -async def test_subnet_buyback(subtensor, mocker): - """Test subnet_buyback extrinsic calls properly.""" +async def test_add_stake_burn(subtensor, mocker): + """Test add_stake_burn extrinsic calls properly.""" # Preps wallet_name = mocker.Mock(spec=Wallet) netuid = 123 hotkey_ss58 = "hotkey" amount = Balance.from_tao(1.0) - mocked_extrinsic = mocker.patch.object(async_subtensor, "subnet_buyback_extrinsic") + mocked_extrinsic = mocker.patch.object(async_subtensor, "add_stake_burn_extrinsic") # Call - result = await subtensor.subnet_buyback(wallet_name, netuid, hotkey_ss58, amount) + result = await subtensor.add_stake_burn(wallet_name, netuid, hotkey_ss58, amount) # Asserts mocked_extrinsic.assert_awaited_once_with( @@ -2952,18 +2952,18 @@ async def test_subnet_buyback(subtensor, mocker): @pytest.mark.asyncio -async def test_subnet_buyback_with_limit_price(subtensor, mocker): - """Test subnet_buyback extrinsic passes limit price.""" +async def test_add_stake_burn_with_limit_price(subtensor, mocker): + """Test add_stake_burn extrinsic passes limit price.""" # Preps wallet_name = mocker.Mock(spec=Wallet) netuid = 123 hotkey_ss58 = "hotkey" amount = Balance.from_tao(1.0) limit_price = Balance.from_tao(2.0) - mocked_extrinsic = mocker.patch.object(async_subtensor, "subnet_buyback_extrinsic") + mocked_extrinsic = mocker.patch.object(async_subtensor, "add_stake_burn_extrinsic") # Call - result = await subtensor.subnet_buyback( + result = await subtensor.add_stake_burn( wallet_name, netuid, hotkey_ss58, amount, limit_price=limit_price ) diff --git a/tests/unit_tests/test_subtensor.py b/tests/unit_tests/test_subtensor.py index 2b4e4eea62..c2f09d784f 100644 --- a/tests/unit_tests/test_subtensor.py +++ b/tests/unit_tests/test_subtensor.py @@ -3182,16 +3182,16 @@ def test_start_call(subtensor, mocker): assert result == mocked_extrinsic.return_value -def test_subnet_buyback(subtensor, fake_wallet, mocker): - """Test subnet_buyback extrinsic calls properly.""" +def test_add_stake_burn(subtensor, fake_wallet, mocker): + """Test add_stake_burn extrinsic calls properly.""" # Preps netuid = 123 hotkey_ss58 = "hotkey" amount = Balance.from_tao(1.0) - mocked_extrinsic = mocker.patch.object(subtensor_module, "subnet_buyback_extrinsic") + mocked_extrinsic = mocker.patch.object(subtensor_module, "add_stake_burn_extrinsic") # Call - result = subtensor.subnet_buyback( + result = subtensor.add_stake_burn( wallet=fake_wallet, netuid=netuid, hotkey_ss58=hotkey_ss58, @@ -3216,17 +3216,17 @@ def test_subnet_buyback(subtensor, fake_wallet, mocker): assert result == mocked_extrinsic.return_value -def test_subnet_buyback_with_limit_price(subtensor, fake_wallet, mocker): - """Test subnet_buyback extrinsic passes limit price.""" +def test_add_stake_burn_with_limit_price(subtensor, fake_wallet, mocker): + """Test add_stake_burn extrinsic passes limit price.""" # Preps netuid = 123 hotkey_ss58 = "hotkey" amount = Balance.from_tao(1.0) limit_price = Balance.from_tao(2.0) - mocked_extrinsic = mocker.patch.object(subtensor_module, "subnet_buyback_extrinsic") + mocked_extrinsic = mocker.patch.object(subtensor_module, "add_stake_burn_extrinsic") # Call - result = subtensor.subnet_buyback( + result = subtensor.add_stake_burn( wallet=fake_wallet, netuid=netuid, hotkey_ss58=hotkey_ss58,