Skip to main content
SUBMIT A PRSUBMIT AN ISSUElast edit: Nov 13, 2025

Working with Proxies

This page covers creating a standard proxy and executing a call from the proxy account.


A standard proxy links a delegator to a known account. The delegator specifies:

  • The delegate account.
  • The allowed ProxyType (scope of permissions).
  • An optional delay.

The delegate has access to funds in the real account and can then execute calls on behalf of the real account within the constraints of the specified ProxyType.

When to use standard proxies

Delegating through a standard proxy is a good option when you want to entrust control to trusted individuals or organizations who can act on your behalf. In this setup, the delegate maintains their own independent signing capability, which allows them to initiate and authorize actions without relying on your key. This approach provides maximum operational flexibility while also making the delegate responsible for managing the security of their own keys.

Prerequisites

  • Real (delegator) account that controls funds and adds the proxy.
  • Delegate account to perform allowed actions.

Add a Proxy

You can add a proxy to authorize another account to perform actions on your behalf. To do this:

import bittensor as bt
from bittensor.core.chain_data.proxy import ProxyType

subtensor = bt.Subtensor()

real_account = bt.Wallet(name="WALLET_NAME") # Your real account
delegate_address = "DELEGATE_ADDRESS" # Your delegate wallet address

response = subtensor.add_proxy(
wallet=real_account,
delegate_ss58=delegate_address,
proxy_type=ProxyType.Any,
delay=0, # optional delay in blocks
)

if response.success:
print(f"✓ Proxy added successfully!")
else:
print(f"✗ Failed: {response.message}")


Your delegate wallet is now authorized to execute small transfers on behalf of the real account.

info

A delegator can assign multiple proxies to the same delegate account. However, each proxy entry must use a unique ProxyType. Attempting to register a duplicate entry with the same delegate and ProxyType will result in a proxy.Duplicate error.

Check an Account’s Proxies

You can check which proxies are associated with an account to see their delegate addresses, proxy types, and any configured delays. To do this:

real_account = bt.Wallet(name="WALLET_NAME")

proxies, deposit = subtensor.get_proxies_for_real_account(
real_account_ss58=real_account.coldkey.ss58_address
)

This returns all the proxies associated to the account and their information—delegate, proxyType, and delay.

Execute a Proxy Call

Use this operation to perform a transaction or call on behalf of another account through an active proxy. When executing a standard proxy, the real account initiates the transaction, but it is signed and authorized by the delegate account.

The following example shows how to execute a transfer call using a proxy. To do this:

import bittensor as bt
from bittensor.core.chain_data.proxy import ProxyType
from bittensor.core.extrinsics.pallets import Balances

subtensor = bt.Subtensor()

real_account = "REAL_ACCOUNT_ADDRESS" # address of the real account
delegate_address = bt.Wallet(name="PROXY_WALLET") # name of the proxy wallet
recipient_wallet = "RECIPIENT_WALLET"

# Create a transfer call
transfer_amount = bt.Balance.from_tao(1.0)
transfer_call = Balances(subtensor).transfer_keep_alive(
dest=recipient_wallet,
value=transfer_amount.rao,
)

# Execute the call through the proxy
response = subtensor.proxy(
wallet=delegate_address, # Proxy signs the transaction
real_account_ss58=real_account, # Real account (origin)
force_proxy_type=ProxyType.Any,
call=transfer_call,
)

if response.success:
print(f"✓ Transfer executed through proxy!")
print(f" Transferred {transfer_amount} from {real_account[:10]}...")
else:
print(f"✗ Failed: {response.message}")
warning

The delegate account must hold enough funds to cover transaction fees, which are approximately 25 µTAO (0.000025 TAO).


Handle delayed proxies

If you configured a non-zero delay when creating a proxy, you must first make an announcement before executing the proxy call. Attempting to execute a proxy call before announcing returns a proxy.Unannounced error.

Generate call hash

Announcing a delayed proxy call requires the hash of the call that you intend to execute. Therefore, you must first generate the call hash of the transaction you want to carry out. To generate the call hash:

import bittensor as bt
from bittensor.core.extrinsics.pallets import Balances

subtensor = bt.Subtensor()

recipient_address = "RECIPIENT_WALLET"

# Create the call you want to execute later
transfer_amount = bt.Balance.from_tao(1.0)
transfer_call = Balances(subtensor).transfer_keep_alive(
dest=recipient_address,
value=transfer_amount.rao,
)

# Get the call hash
call_hash = "0x" + transfer_call.call_hash.hex()

if response.success:
print(f" Call hash: {call_hash}")
else:
print(f"✗ Failed: {response.message}")

Announce a proxy call

Announcing a proxy call publishes the hash of a proxy-call that will be made in the future. To announce a delayed call:

import bittensor as bt
from bittensor.core.chain_data.proxy import ProxyType
from bittensor.core.extrinsics.pallets import Balances

subtensor = bt.Subtensor()

delegate_address = bt.Wallet(name="PROXY_WALLET")
real_account = "REAL_ACCOUNT_ADDRESS"
recipient_address = "RECIPIENT_WALLET"

# Create the call you want to execute later
transfer_amount = bt.Balance.from_tao(1.0)
transfer_call = Balances(subtensor).transfer_keep_alive(
dest=recipient_address,
value=transfer_amount.rao,
)

# Get the call hash
call_hash = "0x" + transfer_call.call_hash.hex()

# Announce the call
response = subtensor.announce_proxy(
wallet=delegate_address,
real_account_ss58=real_account,
call_hash=call_hash,
)

if response.success:
print("✓ Proxy call announced!")
print(f" Call hash: {call_hash}")
else:
print(f"✗ Failed: {response.message}")
info

Next, wait for the duration of the configured delay before executing the call. During the waiting period, the delegate can cancel the announcement—subtensor.remove_proxy_announcement(), while the real account retains final authority to reject it—subtensor.reject_proxy_announcement().


Execute a delayed proxy call

After the announcement waiting period has passed, the delegate account can now execute the proxy if the real account did not reject it. Attempting to execute the proxy before the waiting period passes returns a proxy.Unannounced error. To execute a delayed proxy call:

import bittensor as bt
from bittensor.core.chain_data.proxy import ProxyType
from bittensor.core.extrinsics.pallets import Balances

subtensor = bt.Subtensor()

delegate_address = bt.Wallet(name="PROXY_WALLET")
real_account = "REAL_ACCOUNT_ADDRESS"
recipient_address = "RECIPIENT_ADDRES>"

transfer_amount = bt.Balance.from_tao(1.0)
transfer_call = Balances(subtensor).transfer_keep_alive(
dest=recipient_address,
value=transfer_amount.rao,
)

# Execute the announced call
response = subtensor.proxy_announced(
wallet=delegate_address,
delegate_ss58=delegate_address.coldkeypub.ss58_address,
real_account_ss58=real_account,
force_proxy_type=ProxyType.Any,
call=transfer_call,
)

if response.success:
print("✓ Delayed proxy executed successfully!")
else:
print(f"✗ Failed: {response.message}")

info
  • The call details on the executed proxy must exactly match the original announcement. Any change to the call or call hash will result in a proxy.Unannounced error.
  • Once a delayed proxy call is executed, its announcement is cleared. To execute another proxy with the same details, you must create a new announcement and wait for the waiting period to pass.

Remove a Proxy

Removing a proxy revokes the delegate’s permission to act on behalf of the primary account, effectively ending the proxy relationship on-chain. To remove a proxy:

import bittensor as bt
from bittensor.core.chain_data.proxy import ProxyType

subtensor = bt.Subtensor()

real_account = bt.Wallet(name="WALLET_NAME")
delegate_address = "DELEGATE_ADDRESS"

response = subtensor.remove_proxy(
wallet=real_account,
delegate_ss58=delegate_address,
proxy_type=ProxyType.Any,
delay=0,
)

if response.success:
print("✓ Proxy removed successfully!")
else:
print(f"✗ Failed: {response.message}")
info

The parameters for the proxy being removed must exactly match the proxy type and delay specified when it was added.

Remove all proxies

Use this to remove all proxies associated with an account.

import bittensor as bt

subtensor = bt.Subtensor(network="local")

real_account = bt.Wallet(name="sn-creator")

response = subtensor.remove_proxies(wallet=real_account)

if response.success:
print(f"✓ All proxies removed!")
else:
print(f"✗ Failed: {response.message}")

Troubleshooting

  • proxy.Duplicate: A proxy with the same configuration already exists on the real account. See source code: Duplicate error.
  • proxy.Unannounced: A non-zero delay proxy requires an announcement; announce and wait the delay. See source code: Unannounced error.
  • proxy.Unproxyable/system.CallFiltered: The call is not permitted under the current ProxyType. See source code: Unproxyable error.
  • proxy.TooMany: You exceeded MaxProxies or MaxPending. Remove unused proxies/announcements. See source code: TooMany error.
  • proxy.NotProxy: Ensure you're submitting from the delegate account and referencing the correct real account. See source code: NotProxy error.
  • Token.FundsUnavailable: Ensure that your real account has enough available funds to cover the transaction.