Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
90ecc60
add liquidity exirinsics
Jun 27, 2025
c006ccf
add liquidity utils
Jun 27, 2025
25f3f54
add liquidity utils
Jun 27, 2025
5822962
add subtensor calls
Jun 27, 2025
d64701a
ruff
Jun 27, 2025
26e4bd0
docstring
Jun 27, 2025
ce748e7
SubtensorApi
Jun 27, 2025
04652ec
fix tests with empty methods
Jun 27, 2025
515e0c1
Merge branch 'staging' into feat/roman/liquidity-provider
basfroman Jun 27, 2025
1e3c279
add async extrinsics
Jun 30, 2025
e1824e6
update remove_liquidity_extrinsic
Jun 30, 2025
b33e63a
add async subtensor calls
Jun 30, 2025
955e7ac
improve `bittensor/utils/liquidity.py`
Jun 30, 2025
5d96b12
ruff
Jun 30, 2025
b5fa270
update `get_liquidity_list` (use LiquidityPosition)
Jun 30, 2025
26c5ac7
add `modify_liquidity_extrinsic`
Jun 30, 2025
880eb37
ruff
Jul 1, 2025
462ee83
add `modify_liquidity` methods
Jul 1, 2025
7fe8659
update SubtensorApi
Jul 1, 2025
5996563
improve `get_liquidity_list` methods
Jul 1, 2025
b0d0d13
improve `LiquidityPosition`
Jul 1, 2025
3d2f78e
improve `get_liquidity_list` method
Jul 1, 2025
8721560
remove debug
Jul 1, 2025
7e2e5f1
add unit test for sync `get_liquidity_list`
Jul 1, 2025
322d58f
opps fix async `get_liquidity_list`
Jul 1, 2025
944b3f3
add async unit tests for `get_liquidity_list`
Jul 1, 2025
e42e4e7
fix default arguments for toggle_user_liquidity
Jul 1, 2025
e37405b
fix default arguments for remove_liquidity
Jul 1, 2025
12cc33c
add unit tests for async subtensor
Jul 1, 2025
bb3c9f8
add unit tests for sync subtensor
Jul 1, 2025
8c9fbae
add unit tests for sync extrinsic module
Jul 1, 2025
55f039f
add unit tests for async extrinsic module
Jul 1, 2025
d8c566f
add unit tests for liquidity utils module
Jul 1, 2025
6973c6e
add e2e tests for liquidity logic
Jul 1, 2025
9636136
improve e2e test for non-fast-block
Jul 1, 2025
0deb847
Merge branch 'staging' into feat/roman/liquidity-provider
Jul 1, 2025
84c57b8
Merge branch 'staging' into feat/roman/liquidity-provider
Jul 2, 2025
8d9b245
balance message
Jul 2, 2025
3feab5c
fix `bittensor.utils.liquidity.calculate_fees`
Jul 2, 2025
bf4a8dd
improve Balance error message
Jul 2, 2025
5bc38b8
fix sync extrinsic
Jul 2, 2025
fa1702f
fix async extrinsic
Jul 2, 2025
b765276
fix subtensors
Jul 2, 2025
587050a
fix unit tests
Jul 2, 2025
253b0bd
fix e2e test
Jul 2, 2025
ee90a3e
make e2e test more difficult (add fees checks after add_stake and rem…
Jul 2, 2025
9089c81
add `alpha for non-fast-blocks`
Jul 2, 2025
8349725
Update bittensor/core/async_subtensor.py
basfroman Jul 2, 2025
7864c10
Update bittensor/utils/balance.py
basfroman Jul 2, 2025
3c09578
fix docstrings
Jul 2, 2025
0c747df
fix test
Jul 2, 2025
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
382 changes: 378 additions & 4 deletions bittensor/core/async_subtensor.py

Large diffs are not rendered by default.

231 changes: 231 additions & 0 deletions bittensor/core/extrinsics/asyncex/liquidity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
from typing import Optional, TYPE_CHECKING

from bittensor.utils import unlock_key
from bittensor.utils.balance import Balance
from bittensor.utils.btlogging import logging
from bittensor.utils.liquidity import price_to_tick

if TYPE_CHECKING:
from bittensor_wallet import Wallet
from bittensor.core.async_subtensor import AsyncSubtensor


async def add_liquidity_extrinsic(
subtensor: "AsyncSubtensor",
wallet: "Wallet",
netuid: int,
liquidity: Balance,
price_low: Balance,
price_high: Balance,
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
period: Optional[int] = None,
) -> tuple[bool, str]:
"""
Adds liquidity to the specified price range.

Arguments:
subtensor: The Subtensor client instance used for blockchain interaction.
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.
price_high: The upper bound of the price tick range.
wait_for_inclusion: Whether to wait for the extrinsic to be included in a block. Defaults to True.
wait_for_finalization: Whether to wait for finalization of the extrinsic. Defaults to False.
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.

Returns:
Tuple[bool, str]:
- True and a success message if the extrinsic is successfully submitted or processed.
- False and an error message if the submission fails or the wallet cannot be unlocked.

Note: Adding is allowed even when user liquidity is enabled in specified subnet. Call
`toggle_user_liquidity_extrinsic` to enable/disable user liquidity.
"""
if not (unlock := unlock_key(wallet)).success:
logging.error(unlock.message)
return False, unlock.message

tick_low = price_to_tick(price_low.tao)
tick_high = price_to_tick(price_high.tao)

call = await subtensor.substrate.compose_call(
call_module="Swap",
call_function="add_liquidity",
call_params={
"hotkey": wallet.hotkey.ss58_address,
"netuid": netuid,
"tick_low": tick_low,
"tick_high": tick_high,
"liquidity": liquidity.rao,
},
)

return await subtensor.sign_and_send_extrinsic(
call=call,
wallet=wallet,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
use_nonce=True,
period=period,
)


async def modify_liquidity_extrinsic(
subtensor: "AsyncSubtensor",
wallet: "Wallet",
netuid: int,
position_id: int,
liquidity_delta: Balance,
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
period: Optional[int] = None,
) -> tuple[bool, str]:
"""Modifies liquidity in liquidity position by adding or removing liquidity from it.

Arguments:
subtensor: The Subtensor client instance used for blockchain interaction.
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.
position_id: The id of the position record in the pool.
liquidity_delta: The amount of liquidity to be added or removed (add if positive or remove if negative).
wait_for_inclusion: Whether to wait for the extrinsic to be included in a block. Defaults to True.
wait_for_finalization: Whether to wait for finalization of the extrinsic. Defaults to False.
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.

Returns:
Tuple[bool, str]:
- True and a success message if the extrinsic is successfully submitted or processed.
- False and an error message if the submission fails or the wallet cannot be unlocked.

Note: Modifying is allowed even when user liquidity is enabled in specified subnet.
Call `toggle_user_liquidity_extrinsic` to enable/disable user liquidity.
"""
if not (unlock := unlock_key(wallet)).success:
logging.error(unlock.message)
return False, unlock.message

call = await subtensor.substrate.compose_call(
call_module="Swap",
call_function="modify_position",
call_params={
"hotkey": wallet.hotkey.ss58_address,
"netuid": netuid,
"position_id": position_id,
"liquidity_delta": liquidity_delta.rao,
},
)

return await subtensor.sign_and_send_extrinsic(
call=call,
wallet=wallet,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
use_nonce=True,
period=period,
)


async def remove_liquidity_extrinsic(
subtensor: "AsyncSubtensor",
wallet: "Wallet",
netuid: int,
position_id: int,
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
period: Optional[int] = None,
) -> tuple[bool, str]:
"""Remove liquidity and credit balances back to wallet's hotkey stake.

Arguments:
subtensor: The Subtensor client instance used for blockchain interaction.
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.
position_id: The id of the position record in the pool.
wait_for_inclusion: Whether to wait for the extrinsic to be included in a block. Defaults to True.
wait_for_finalization: Whether to wait for finalization of the extrinsic. Defaults to False.
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.

Returns:
Tuple[bool, str]:
- True and a success message if the extrinsic is successfully submitted or processed.
- False and an error message if the submission fails or the wallet cannot be unlocked.

Note: Adding is allowed even when user liquidity is enabled in specified subnet.
Call `toggle_user_liquidity_extrinsic` to enable/disable user liquidity.
"""
if not (unlock := unlock_key(wallet)).success:
logging.error(unlock.message)
return False, unlock.message

call = await subtensor.substrate.compose_call(
call_module="Swap",
call_function="remove_liquidity",
call_params={
"hotkey": wallet.hotkey.ss58_address,
"netuid": netuid,
"position_id": position_id,
},
)

return await subtensor.sign_and_send_extrinsic(
call=call,
wallet=wallet,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
use_nonce=True,
period=period,
)


async def toggle_user_liquidity_extrinsic(
subtensor: "AsyncSubtensor",
wallet: "Wallet",
netuid: int,
enable: bool,
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
period: Optional[int] = None,
) -> tuple[bool, str]:
"""Allow to toggle user liquidity for specified subnet.

Arguments:
subtensor: The Subtensor client instance used for blockchain interaction.
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.
enable: Boolean indicating whether to enable user liquidity.
wait_for_inclusion: Whether to wait for the extrinsic to be included in a block. Defaults to True.
wait_for_finalization: Whether to wait for finalization of the extrinsic. Defaults to False.
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.

Returns:
Tuple[bool, str]:
- True and a success message if the extrinsic is successfully submitted or processed.
- False and an error message if the submission fails or the wallet cannot be unlocked.
"""
if not (unlock := unlock_key(wallet)).success:
logging.error(unlock.message)
return False, unlock.message

call = await subtensor.substrate.compose_call(
call_module="Swap",
call_function="toggle_user_liquidity",
call_params={"netuid": netuid, "enable": enable},
)

return await subtensor.sign_and_send_extrinsic(
call=call,
wallet=wallet,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
period=period,
)
Loading