Account Permission Management
How TRON accounts support multi-party control through weighted permissions and signature thresholds.
A TRON account does not need to be controlled by a single private key. Through Account Permission Management (TIP-16), an account can be jointly operated by multiple parties — each holding their own keys, each with a configurable weight, and each transaction authorized only when the sum of signatures meets a threshold.
This page covers the three permission types, the threshold-and-weight model, the structure of the permission update contract, the operations bitmap that restricts active permissions to specific contract types, and the fees charged for permission updates and multi-signed transactions.
Prerequisites
Permission types
Each TRON account has three permission slots:
| Permission | Default purpose | Notes |
|---|---|---|
| Owner | Full control — can execute any contract type and modify the account's own permissions | Default permission for new accounts |
| Witness | Used by Super Representative (SR) accounts to sign block production | Must contain exactly 1 key; cannot authorize normal contract transactions |
| Active | Custom-scoped permissions for delegated operation | Up to 8 active permissions per account |
The proto-level name witness_permission is the same as what TRON prose calls "Super Representative (SR) permission". This page uses Witness when referring to the permission type (matching the code), and SR when discussing the role. For the broader witness-vs-SR convention, see Consensus and DPoS.
Threshold and weight
A permission is authorized when the sum of signing weights meets or exceeds the threshold. Each permission is configured with:
- A threshold — a positive integer
- A list of keys, each with a base58 address and a weight (
int64)
When a transaction is signed, the network recovers the signing addresses, looks them up in the relevant permission's keys list, sums the weights of the recognized signers, and checks the sum against the threshold.
The configuration must satisfy these constraints (enforced at AccountPermissionUpdateContract validation):
| Rule | Detail |
|---|---|
| Max keys per permission | Fixed at 5 |
| Distinct addresses | A keys list cannot contain the same address twice |
| Positive weights | Each key's weight > 0 |
| Sum ≥ threshold | The sum of all key weights must be at least the threshold (otherwise threshold is unreachable) |
permission_name length | At most 32 bytes |
parent_id | Must be 0 |
| Witness permission single-key | Witness type permissions must contain exactly 1 key |
Single-signer (default)
A new account starts with a single-signer owner permission:
threshold: 1
keys:
- address: <account's own address>, weight: 1A transaction signed by the account's private key produces a sum of 1, meeting the threshold, and is authorized.
Multi-party
A 2-of-3 owner permission across three parties:
threshold: 2
keys:
- address: TKey1...AA, weight: 1
- address: TKey2...BB, weight: 1
- address: TKey3...CC, weight: 1Any two of the three signers can authorize a transaction.
Weighted
Different parties can hold different authority levels:
threshold: 3
keys:
- address: TFounder...A, weight: 2
- address: TCofnd1...B, weight: 1
- address: TCofnd2...C, weight: 1A founder (weight 2) plus any one cofounder (weight 1) reaches threshold 3. Either cofounder alone (weight 1) does not. Both cofounders working without the founder (1 + 1 = 2) does not.
Active permissions and contract restrictions
Active permissions go beyond simple multi-sig: each active permission carries an operations field that restricts which contract types it may execute. This lets you grant a delegate the authority to perform specific actions without exposing the full owner permission.
The operations field is a 32-byte (256-bit) bitmap encoded little-endian. Each bit corresponds to a ContractType value from Tron.proto. Contract type ID n is bit (n & 7) of byte n / 8:
- ID
0→ byte 0, bit 0 (least-significant bit of first byte) - ID
7→ byte 0, bit 7 - ID
8→ byte 1, bit 0 - ID
59→ byte 7, bit 3
A bit set to 1 means "this permission can execute this contract type". A bit set to 0 means "this contract type is forbidden under this permission".
Contract type IDs
Every TRON contract type has a numeric ID from the Transaction.Contract.ContractType proto enum. The table below lists popular transaction supported on mainnet:
| ID | ContractType | Description |
|---|---|---|
| 0 | AccountCreateContract | Create an account |
| 1 | TransferContract | Transfer TRX |
| 2 | TransferAssetContract | Transfer a TRC-10 token |
| 4 | VoteWitnessContract | Vote for a Super Representative |
| 5 | WitnessCreateContract | Apply to become an SR candidate |
| 11 | FreezeBalanceContract | Stake 1.0 — stake TRX |
| 12 | UnfreezeBalanceContract | Stake 1.0 — unstake TRX |
| 13 | WithdrawBalanceContract | Withdraw voting rewards |
| 16 | ProposalCreateContract | Create a governance proposal |
| 17 | ProposalApproveContract | Approve a proposal |
| 30 | CreateSmartContract | Deploy a smart contract |
| 31 | TriggerSmartContract | Call a smart contract |
| 33 | UpdateSettingContract | Update consume_user_resource_percent |
| 45 | UpdateEnergyLimitContract | Adjust the Energy limit a deployer subsidizes |
| 46 | AccountPermissionUpdateContract | Update account permissions |
| 48 | ClearABIContract | Clear a contract's ABI |
| 49 | UpdateBrokerageContract | Update SR brokerage rate |
| 54 | FreezeBalanceV2Contract | Stake 2.0 — stake TRX |
| 55 | UnfreezeBalanceV2Contract | Stake 2.0 — unstake TRX |
| 56 | WithdrawExpireUnfreezeContract | Withdraw unstaked TRX after the cooldown |
| 57 | DelegateResourceContract | Delegate Bandwidth or Energy |
| 58 | UnDelegateResourceContract | Cancel resource delegation |
| 59 | CancelAllUnfreezeV2Contract | Cancel all pending unstake operations |
Source:
protocol/src/main/protos/core/Tron.protoenum ContractType. The list reflects the protocol as of java-tron v4.8+. For the source-of-truth enum, also see Details of supported transaction types.
Computing the operations bitmap
To allow a permission to execute, say, TRX transfers (ID 1), SR voting (ID 4), and Stake 2.0 staking (ID 54), compute the bitmap by setting bits 1, 4, and 54:
import org.bouncycastle.util.encoders.Hex;
int[] contractIds = { 1, 4, 54 }; // TransferContract, VoteWitnessContract, FreezeBalanceV2Contract
byte[] operations = new byte[32];
for (int id : contractIds) {
operations[id / 8] |= (byte) (1 << (id % 8));
}
System.out.println(Hex.toHexString(operations));
// "1200000000004000000000000000000000000000000000000000000000000000"Decode in the reverse direction:
public static List<Integer> decodeOperations(String operationsHex) {
byte[] ops = Hex.decode(operationsHex);
List<Integer> ids = new ArrayList<>();
for (int i = 0; i < ops.length; i++) {
for (int bit = 0; bit < 8; bit++) {
if ((ops[i] >> bit & 0x1) == 1) {
ids.add(i * 8 + bit);
}
}
}
return ids;
}Worked encoding examples
| Operations allowed | Binary (big-endian by byte, low bit first within each byte) | Hex (little-endian byte order) |
|---|---|---|
| TransferContract (ID 1) + VoteWitnessContract (ID 4) | 00010010 00000000 00000000 … | 12 00 00 … |
| TransferContract (ID 1) + UpdateAssetContract (ID 15) | 00000010 10000000 00000000 … | 02 80 00 … |
| All system contracts (per Mainnet defaults) | 01111111 11111111 00011111 … | 7F FF 1F … |
Decoding a hex string by eye: read each byte as a binary nibble pair, with the least-significant bit being the lowest contract ID for that byte. Byte 0's bit 0 = contract type ID 0; byte 0's bit 7 = ID 7; byte 1's bit 0 = ID 8; and so on.
Use case: a hot key for transfers only
A treasury account's owner permission is held by a multi-sig group. To pay routine vendor invoices without convening the multi-sig every time, the treasury creates an active permission with:
- A single-signer threshold (e.g.,
threshold: 1, one delegate key withweight: 1) - An
operationsbitmap that allows onlyTransferContract(ID 1) — hex02 00 00 … - All other contract types disabled — the delegate cannot stake, vote, deploy contracts, or modify permissions
The delegate's hot key can sign vendor transfers, but cannot perform any other operation. The owner permission remains in cold storage.
Updating permissions
To modify any permission, the account submits an AccountPermissionUpdateContract transaction. This contract overwrites all three permission slots at once — even if you only want to change one, you must include the other two unchanged in the contract body:
message AccountPermissionUpdateContract {
bytes owner_address = 1;
Permission owner = 2;
Permission witness = 3;
repeated Permission actives = 4;
}| Field | Description |
|---|---|
owner_address | The account being modified |
owner | The new owner permission (required, not optional) |
witness | The new Witness permission (only meaningful for SR accounts; otherwise null) |
actives | The new list of active permissions (up to 8) |
The transaction must be signed under the account's existing owner permission.
Permission_id in transactions
Every transaction declares which permission level it is signed under via Permission_id in the contract body:
| Permission_id | Permission |
|---|---|
| 0 | Owner permission (default if omitted) |
| 1 | Witness permission — reserved for SR block production; cannot authorize normal contract transactions |
| 2–9 | Active permissions, in the order they were added to the account |
The id of an active permission is automatically assigned by the network in sequence starting at 2. For any Permission_id != 0, the permission's type must equal Active and the requested contract type must be allowed by the operations bitmap; otherwise the transaction is rejected with Permission type is wrong! or Permission denied!.
Fees
Permission management on TRON charges two kinds of fees. Both are dynamic chain parameters and can be adjusted by governance proposal — query the live values via wallet/getchainparameters rather than hard-coding them.
| Fee | Chain parameter | Current Mainnet default | When charged |
|---|---|---|---|
| Update account permissions | #22 getUpdateAccountPermissionFee | 100 TRX (100,000,000 sun) | Every AccountPermissionUpdateContract transaction |
| Multi-signature surcharge | #23 getMultiSignFee | 1 TRX (1,000,000 sun) | Charged once when a transaction carries two or more signatures |
Both fees are added on top of the normal Bandwidth or Energy cost of the transaction.
Worked example: 2-of-3 multi-sig setup
To configure a 2-of-3 owner permission on an account, send an AccountPermissionUpdateContract with:
{
"owner_address": "TYourAccount...XX",
"owner": {
"type": 0,
"id": 0,
"permission_name": "owner",
"threshold": 2,
"keys": [
{ "address": "TKey1...AA", "weight": 1 },
{ "address": "TKey2...BB", "weight": 1 },
{ "address": "TKey3...CC", "weight": 1 }
]
},
"witness": null,
"actives": [
{
"type": 2,
"id": 2,
"permission_name": "active0",
"threshold": 1,
"operations": "7fff1fc0037e0000000000000000000000000000000000000000000000000000",
"keys": [
{ "address": "TKey1...AA", "weight": 1 }
]
}
]
}After this transaction confirms, all owner-level operations on the account require any two of the three keys. The active0 permission (id 2) lets TKey1 execute the operations enabled by the operations bitmap on its own — a hot-key path for routine work.
For the end-to-end transaction flow with multi-party signing, see Account Permission Management transaction example.
Limits
| Limit | Value |
|---|---|
| Maximum keys per permission | Fixed at 5 |
| Maximum active permissions per account | 8 (hardcoded) |
permission_name length | 32 bytes |
Permission_id range | 0–9 (0 = owner, 1 = Witness, 2–9 = active) |
| Witness permission key count | Must be exactly 1 |
Active permission parent_id | Must be 0 |
APIs
| API | Description |
|---|---|
wallet/accountpermissionupdate | Update account permissions |
wallet/getsignweight | Inspect collected signature weight on a partial transaction |
wallet/getapprovedlist | List addresses that have signed |
wallet/broadcasttransaction | Submit a fully-signed transaction |
Related resources
- Account Permission Management transaction example — End-to-end multi-sig walkthrough
- Signature validation — How signatures are checked
- Accounts and keys — Account basics
- Details of supported transaction types — Full
ContractTypereference - TIP-16 — The original specification
Updated 8 days ago