Skip to main content
SUBMIT A PRSUBMIT AN ISSUElast edit: Dec 08, 2025

Understanding Pure Proxies

This page covers creating a pure proxy and executing a call using a pure proxy. The primary use case for pure proxies is constructing multisignature wallets (multisigs) with swappable members. For most other applications requiring wallet indirection, regular proxy wallets are the correct solution.

See:

Overview of pure proxies

Pure proxies are keyless, non-deterministic accounts that are created fresh using the createPure extrinsic. They represent a unique approach to account delegation where:

  • The proxy account has no private key and cannot sign transactions independently
  • The proxy can only act through its delegator—all operations must be initiated by the delegator
  • The account is completely isolated and cannot escalate its own permissions

Pure proxies are unlike standard proxies, where the proxy can access the real account's funds to execute calls on their behalf. A pure proxy account must hold its own funds, while the spawner account acts as an Any proxy for it, signing and authorizing transactions on the proxy's behalf.

It is critical to understand that pure proxies do not offer the security advantage of regular proxy wallets, which is to allow a single, less sensitive wallet to perform operations on behalf of a more valuable wallet, allowing the more sensitive wallet to remain protected behind more stringent access security. Instead, the main application of pure proxies is to solve an operational problem posed by multisig wallets, as described below.

Transaction flow in pure proxies

All transactions involving a pure proxy must be signed by the spawner account. Once signed, the transaction is executed on-chain as if it originated directly from the pure proxy. Unlike standard proxies, a pure proxy must hold its own funds to cover fees or transfers. The spawner then acts as an Any proxy, handling the signing and authorization of calls, but the balance used comes from the pure proxy's account.

Multisigs and Pure Proxies

Multisignature wallets offer a unique security advantage (see Secure a Coldkey with a Multisig Wallet). However, the unique mechanism that underlies them cryptographically presents an operational difficulty. A multisig address is deterministically derived from its members. If you create a 2-of-3 multisig with Alice, Bob, and Charlie, you get a specific address. Therefore, if Charlie leaves and Dave joins, you must create an entirely new multisig with a new address—then transfer all funds and update all references.

Pure proxies offer a workaround; instead of basing the multisig on people's coldkeys directly, you can base it off or pure proxies controlled by the members of a multisig, you can make pure proxies the members:

Multisig (Any 2 of 3 signatures required to sign transaction)
├── Pure Proxy A ← controlled by Alice
├── Pure Proxy B ← controlled by Bob
└── Pure Proxy C ← controlled by Charlie

When Charlie leaves and Dave joins:

  1. Charlie transfers control of Pure Proxy C to Dave
  2. Dave now controls Pure Proxy C, allowing him to co-sign transactions with either Alice or Bob. Charlie's key is now unable to co-sign.
  3. The multisig itself never changes—same address, same members (the pure proxies)

This approach means you never need to recreate the multisig or transfer funds when team members change. The pure proxy addresses remain constant; only who controls each pure proxy changes.

Transferring control of a pure proxy

You can transfer control of a pure proxy to a new account by:

  1. Adding the new account as an Any type proxy for the pure proxy
  2. Removing the old controller as proxy

This is how you swap members in a multisig-of-pure-proxies setup: the outgoing member adds the incoming member as a proxy for their pure proxy, then removes themselves. See source code: pure proxy account generation.

Prerequisites

Before creating a pure proxy, ensure you have a spawner account that will initialize and control the pure proxy.

Create a pure proxy

The proxy::createPure extrinsic creates a pure proxy. See source code: createPure implementation.

Use this operation to generate a pure proxy account:

btcli proxy create \
--wallet.name WALLET_NAME \
--proxy-type Any \
--delay 0 \
--index 0

Parameters:

  • --wallet.name: Your wallet name (the spawner account that will control the proxy)
  • --proxy-type: The type of proxy (e.g., Any, Staking, Transfer, etc.)
  • --delay: Optional delay in blocks (0 for immediate execution)
  • --index: Disambiguation index for creating unique addresses (usually 0)

Example output:

Created pure '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty' 
from spawner '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
with proxy type 'Any' with delay 0.

Extrinsic hash: 0xcd5ded2dfc505152870610233532646f6ebdd930793fa82f999d9bda2b79c2b5
Block: 1234567
Extrinsic index: 2
Save creation details

Record the following values from the output—you'll need them to kill the proxy later:

  • Pure proxy address
  • Block number (height)
  • Extrinsic index
  • The index value you used
  • The proxy type you chose

BTCLI will prompt you to save this to your address book for convenience.

Save to address book:

# Optionally add to your local address book
btcli config add-proxy \
--name my-pure-proxy \
--address 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty \
--proxy-type Any \
--spawner 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY \
--delay 0

Creating a pure proxy adds the spawner account as the first delegate for that proxy. Additional delegates can also be added by registering new proxy entries from the pure proxy account, each specifying the delegate account, proxy type, etc.

Executing calls via a pure proxy

When executing a pure proxy, the proxy account initiates the transaction, but it is signed and authorized by the spawner account. In practice, the proxy account is treated as the real account during execution.

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

With pure proxies in BTCLI, use the --proxy flag with the pure proxy address as the value, and sign with the spawner wallet:

# Example: Transfer funds from the pure proxy
btcli wallet transfer \
--wallet.name spawner_wallet \
--proxy PURE_PROXY_ADDRESS \
--dest RECIPIENT_ADDRESS \
--amount 1.0

How it works:

  • --wallet.name spawner_wallet: The spawner wallet signs the transaction
  • --proxy PURE_PROXY_ADDRESS: The pure proxy account acts as the origin
  • The transfer will appear to come from the pure proxy address
  • Funds are deducted from the pure proxy's balance

Using saved proxies: If you saved the pure proxy to your address book:

btcli wallet transfer \
--wallet.name spawner_wallet \
--proxy my-pure-proxy \
--dest RECIPIENT_ADDRESS \
--amount 1.0
Pure proxy must be funded

Ensure the pure proxy account has enough funds to cover both the transfer amount and transaction fees. Transfer funds to the pure proxy first using a regular transfer.

Other operations through pure proxies:

# Add stake through pure proxy
btcli stake add \
--wallet.name spawner_wallet \
--proxy PURE_PROXY_ADDRESS \
--netuid 0 \
--amount 10.0

# Remove stake through pure proxy
btcli stake remove \
--wallet.name spawner_wallet \
--proxy PURE_PROXY_ADDRESS \
--netuid 0 \
--amount 5.0

Kill a pure proxy

Killing a pure proxy requires the proxy account address, the spawner account, and the proxy's complete creation details—the block height, extrinsic index, and the disambiguation index used during creation. Once executed, the pure proxy is permanently removed, and any funds remaining in the proxy account are lost.

Pure proxies are killed using the killPure extrinsic as shown. See source code: killPure implementation:

Permanent deletion

Killing a pure proxy permanently deletes the pure proxy account. Any funds remaining in the account will be permanently lost. Make sure to transfer all funds out before killing the proxy.

BTCLI will prompt you for confirmation with the text "KILL" to proceed.

btcli proxy kill \
--wallet.name SPAWNER_WALLET \
--height BLOCK_NUMBER \
--ext-index EXTRINSIC_INDEX \
--proxy-type Any \
--index 0 \
--spawner SPAWNER_ADDRESS

Required Parameters:

  • --wallet.name: The spawner wallet that created the proxy
  • --height: The block number where the pure proxy was created
  • --ext-index: The extrinsic index of the creation transaction
  • --proxy-type: Must match the type used when creating (e.g., Any)
  • --index: Must match the index used when creating (usually 0)
  • --spawner: The SS58 address of the spawner account

Example:

Suppose we created a pure proxy and received output as follows:

 btcli proxy create \
--wallet.name PracticeSafeWallet \
--proxy-type Transfer \
--delay 0 \
--index 0

This will create a Pure Proxy of type Transfer. Do you want to proceed? [y/n]: y
Enter your password:
Decrypting...
l✅ Your extrinsic has been included as 5960138-7
Created pure '5DvEUipraHsk26renzART8NKuskd3yacsJq64wKHRGTpncCn' from spawner '5CS9x5NsPHpb2THeS92zBYCSSk4MFoQjjx76DB8bEzeJTTSt' with proxy type 'Transfer' with delay 0.

We use the block number/extrinsic index as follows when identifying the pure proxy to kill:

btcli proxy kill \
--wallet.name PracticeSafeWallet \
--proxy-type Transfer \
--spawner 5CS9x5NsPHpb2THeS92zBYCSSk4MFoQjjx76DB8bEzeJTTSt

Enter the block number at which the proxy was created: 5960138
Enter the extrinsic index of the `btcli proxy create` event.: 5960138

This will kill a Pure Proxy account of type Transfer.
All access to this account will be lost. Any funds held in it will be inaccessible.To proceed, enter KILL: KILL
Enter your password:
Decrypting...
✅Success!

Troubleshooting

  • Token.FundsUnavailable: Ensure that the pure proxy account has been funded and has enough funds to cover the transfer.
  • proxy.NotProxy: Ensure you're executing the pure proxy correctly—from the creator account and referencing the pure proxy account as real. See source code: NotProxy error.
  • Proxy.NoPermission: The killPure call is not permitted under the current. See source code: NoPermission error.
  • system.CallFiltered: The call is not permitted under the current ProxyType.