-
Notifications
You must be signed in to change notification settings - Fork 473
Proxy System Overview
graph LR
subgraph "ProxyDefinition stored in Proxies storage, keyed by delegator"
PD["delegate: AccountId
proxy_type: ProxyType
delay: BlockNumber"]
end
Delegator["Delegator (aka real)
───────────────
Owns the account.
Creates/removes proxies.
Pays proxy deposit."]
Delegate["Delegate
───────────────
Signs transactions
on behalf of delegator.
Limited by proxy_type."]
Delegator -- "add_proxy / remove_proxy" --> PD
PD -- "authorizes" --> Delegate
Delegate -- "proxy(real, call)" --> Delegator
sequenceDiagram
participant D as Delegator (real)
participant Chain as On-chain Storage
participant P as Delegate
Note over D: Signs with own key
D->>Chain: add_proxy(delegate, proxy_type, delay)
Note over Chain: Proxies[delegator] += ProxyDefinition<br/>Reserve deposit from delegator
alt delay = 0 (immediate)
Note over P: Signs with delegate key
P->>Chain: proxy(real=delegator, call)
Chain->>Chain: find_proxy -> check proxy_type.filter(call) -> execute as delegator
else delay > 0 (deferred)
P->>Chain: announce(real=delegator, call_hash)
Note over Chain: Announcements[delegate] += {real, call_hash, height}<br/>Reserve announcement deposit from delegate
Note over Chain: Wait >= delay blocks
Note over D: Optional: can veto
D-->>Chain: reject_announcement(delegate, call_hash)
Note over P,Chain: After delay blocks pass:
P->>Chain: proxy_announced(delegate, real, call)
Chain->>Chain: find_proxy -> check delay elapsed -> execute as delegator
end
D->>Chain: remove_proxy(delegate, proxy_type, delay)
Note over Chain: Remove from Proxies[delegator]<br/>Unreserve deposit<br/>Does NOT clean Announcements
sequenceDiagram
participant S as Spawner
participant Chain as On-chain Storage
participant Pure as Pure Account (no private key)
S->>Chain: create_pure(proxy_type, delay, index)
Note over Chain: Derive address: hash(spawner, height, ext_index, proxy_type, index)<br/>Proxies[pure] = [{delegate: spawner, proxy_type, delay}]<br/>Reserve deposit from spawner
Chain-->>Pure: Pure account now exists
Note over S: Control pure via proxy call
S->>Chain: proxy(real=pure, call=any allowed call)
Chain->>Chain: Execute call as pure account
Note over S: To destroy (proxy_type MUST be Any):
S->>Chain: proxy(real=pure, call=kill_pure(spawner, ...))
Note over Chain: Verify caller is the pure account<br/>Remove Proxies[pure]<br/>Unreserve deposit to spawner
Note over Pure: Account permanently inaccessible.<br/>Any remaining funds are lost forever.
graph TB
subgraph "Deposits -- reserved, returned on removal"
PD["Proxy Deposit
Paid by: Delegator
When: add_proxy
Returned: remove_proxy / remove_proxies"]
PPD["Pure Proxy Deposit
Paid by: Spawner
When: create_pure
Returned: kill_pure"]
AD["Announcement Deposit
Paid by: Delegate
When: announce
Returned: proxy_announced / remove_announcement / reject_announcement"]
end
subgraph "Transaction Fees"
DF["Default: Delegate pays
-- the account that signs the tx"]
RF["set_real_pays_fee -- delegate, true:
Delegator pays fees for
this delegate proxy calls"]
NF["proxy_announced:
set_real_pays_fee does NOT apply.
Signer always pays."]
end
graph TD
Any["Any
All calls allowed.
Only type that can call
kill_pure and remove_proxies"]
NonTransfer["NonTransfer"]
NonCritical["NonCritical"]
Staking["Staking"]
Transfer["Transfer"]
SmallTransfer["SmallTransfer"]
Registration["Registration"]
Owner["Owner"]
ChildKeys["ChildKeys"]
SwapHotkey["SwapHotkey"]
RootClaim["RootClaim"]
NonFungible["NonFungible"]
SubnetLeaseBeneficiary["SubnetLeaseBeneficiary"]
SudoUncheckedSetCode["SudoUncheckedSetCode"]
Any -- "superset of" --> NonTransfer
Any -- "superset of" --> NonCritical
Any -- "superset of" --> Staking
Any -- "superset of" --> Transfer
Any -- "superset of" --> Registration
Any -- "superset of" --> Owner
Any -- "superset of" --> ChildKeys
Any -- "superset of" --> SwapHotkey
Any -- "superset of" --> RootClaim
Any -- "superset of" --> NonFungible
Any -- "superset of" --> SubnetLeaseBeneficiary
Any -- "superset of" --> SudoUncheckedSetCode
NonTransfer -- "superset of" --> Staking
NonTransfer -- "superset of" --> Registration
NonTransfer -- "superset of" --> Owner
NonTransfer -- "superset of" --> NonCritical
NonTransfer -- "superset of" --> ChildKeys
NonTransfer -- "superset of" --> SwapHotkey
NonTransfer -- "superset of" --> RootClaim
NonTransfer -- "superset of" --> NonFungible
NonTransfer -- "superset of" --> SubnetLeaseBeneficiary
NonTransfer -- "superset of" --> SudoUncheckedSetCode
NonTransfer -. "NOT superset of" .-> Transfer
NonTransfer -. "NOT superset of" .-> SmallTransfer
Transfer -- "superset of" --> SmallTransfer
graph LR
subgraph "Blocked by do_proxy"
B1["add_proxy with broader type:
BLOCKED if delegate proxy_type
is NOT superset of the new type"]
B2["remove_proxy with broader type:
same rule as above"]
B3["remove_proxies / kill_pure:
BLOCKED unless proxy_type = Any"]
end
subgraph "Example"
E1["Delegate has Staking proxy:
-- cannot add_proxy with Any
-- cannot add_proxy with Transfer
-- can add_proxy with Staking"]
end
| Extrinsic | Signed by | Effect |
|---|---|---|
add_proxy(delegate, type, delay) |
Delegator | Add delegate |
remove_proxy(delegate, type, delay) |
Delegator | Remove specific delegate |
remove_proxies() |
Delegator | Remove all delegates |
proxy(real, force_type, call) |
Delegate | Immediate call as delegator (delay=0) |
announce(real, call_hash) |
Delegate | Announce future call (delay>0) |
proxy_announced(delegate, real, type, call) |
Anyone | Execute announced call after delay |
reject_announcement(delegate, call_hash) |
Delegator | Veto a pending announcement |
remove_announcement(real, call_hash) |
Delegate | Cancel own announcement |
create_pure(type, delay, index) |
Spawner | Create keyless account |
kill_pure(spawner, type, index, height, ext_index) |
Pure (via proxy) | Destroy pure account |
set_real_pays_fee(delegate, pays_fee) |
Delegator | Toggle fee payer for proxy calls |
Source: runtime/src/lib.rs L612-L828
Filter: allow-list -- allows ALL calls.
The most permissive type. Required as the default by the pallet. Only proxy type that can execute kill_pure and remove_proxies through a proxy call.
Allows: everything EXCEPT the following:
| Blocked call |
|---|
Balances::* (all balance transfer calls) |
SubtensorModule::transfer_stake |
SubtensorModule::schedule_swap_coldkey |
SubtensorModule::swap_coldkey |
Allows: everything EXCEPT the following:
| Blocked call |
|---|
SubtensorModule::dissolve_network |
SubtensorModule::root_register |
SubtensorModule::burned_register |
Sudo::* |
Allows: everything EXCEPT calls that move TAO/Alpha or change key ownership:
| Blocked call |
|---|
Balances::* |
SubtensorModule::add_stake |
SubtensorModule::add_stake_limit |
SubtensorModule::remove_stake |
SubtensorModule::remove_stake_limit |
SubtensorModule::remove_stake_full_limit |
SubtensorModule::unstake_all |
SubtensorModule::unstake_all_alpha |
SubtensorModule::swap_stake |
SubtensorModule::swap_stake_limit |
SubtensorModule::move_stake |
SubtensorModule::transfer_stake |
SubtensorModule::burned_register |
SubtensorModule::root_register |
SubtensorModule::schedule_swap_coldkey |
SubtensorModule::swap_coldkey |
SubtensorModule::swap_hotkey |
Allows ONLY:
| Allowed call |
|---|
SubtensorModule::add_stake |
SubtensorModule::remove_stake |
SubtensorModule::unstake_all |
SubtensorModule::unstake_all_alpha |
SubtensorModule::swap_stake |
SubtensorModule::swap_stake_limit |
SubtensorModule::move_stake |
SubtensorModule::add_stake_limit |
SubtensorModule::remove_stake_limit |
SubtensorModule::remove_stake_full_limit |
SubtensorModule::set_root_claim_type |
Note: transfer_stake is NOT included. A leaked Staking proxy cannot move funds out of the account.
Allows ONLY:
| Allowed call |
|---|
Balances::transfer_keep_alive |
Balances::transfer_allow_death |
Balances::transfer_all |
SubtensorModule::transfer_stake |
Same calls as Transfer, but each call is checked against a per-call amount limit:
-
Balances::transfer_keep_alive/transfer_allow_death:value < 0.5 TAO(500,000,000 RAO) -
SubtensorModule::transfer_stake:alpha_amount < 0.5 Alpha(500,000,000)
Any call exceeding the limit is rejected.
Allows ONLY:
| Allowed call |
|---|
AdminUtils::* (all admin utils calls EXCEPT sudo_set_sn_owner_hotkey) |
SubtensorModule::set_subnet_identity |
SubtensorModule::update_symbol |
Allows ONLY:
| Allowed call |
|---|
SubtensorModule::burned_register |
SubtensorModule::register |
Allows ONLY:
| Allowed call |
|---|
SubtensorModule::set_children |
SubtensorModule::set_childkey_take |
Allows ONLY:
| Allowed call |
|---|
SubtensorModule::swap_hotkey |
Allows ONLY:
| Allowed call |
|---|
SubtensorModule::claim_root |
Allows ONLY:
| Allowed call |
|---|
Sudo::sudo_unchecked_weight wrapping System::set_code
|
Any other call inside sudo_unchecked_weight, or any call outside of it, is rejected.
Allows ONLY:
| Allowed call |
|---|
SubtensorModule::start_call |
AdminUtils::sudo_set_serving_rate_limit |
AdminUtils::sudo_set_min_difficulty |
AdminUtils::sudo_set_max_difficulty |
AdminUtils::sudo_set_weights_version_key |
AdminUtils::sudo_set_adjustment_alpha |
AdminUtils::sudo_set_immunity_period |
AdminUtils::sudo_set_min_allowed_weights |
AdminUtils::sudo_set_kappa |
AdminUtils::sudo_set_rho |
AdminUtils::sudo_set_activity_cutoff |
AdminUtils::sudo_set_network_registration_allowed |
AdminUtils::sudo_set_network_pow_registration_allowed |
AdminUtils::sudo_set_max_burn |
AdminUtils::sudo_set_bonds_moving_average |
AdminUtils::sudo_set_bonds_penalty |
AdminUtils::sudo_set_commit_reveal_weights_enabled |
AdminUtils::sudo_set_liquid_alpha_enabled |
AdminUtils::sudo_set_alpha_values |
AdminUtils::sudo_set_commit_reveal_weights_interval |
AdminUtils::sudo_set_toggle_transfer |
| Type | Status |
|---|---|
Triumvirate |
deprecated, filter returns false
|
Senate |
deprecated, filter returns false
|
Governance |
deprecated, filter returns false
|
RootWeights |
deprecated, filter returns false
|