TRON Multi-Signature Mechanism

TRON Core Devs
Published in
9 min readDec 27, 2019



Standard transactions on cryptocurrency networks can be called single-signature transactions because they require only one digital signature for a transaction to be done. Multi-signature gives every signature one weight, the signatures’ total weight of the transactions must reach the customized weight threshold before they can be executed. By multi-signature, an account can be managed by several private keys, and the transactions created in one account can be signed by serval private keys. This document discuss multi-signature operation permission specification and how to implement user-defined operation permission for multi-signature.


The scheme includes three kinds of permission, owner-permission, witness-permission, and active-permission, where owner-permission has the authority to execute all contracts, witness-permission is used for generating blocks, and active-permission is custom permission (a combination of contracts permission sets).


Lets’ see several cases:

Alice is running a company, she creates an account as her company fund account. Alice adds Bob(Accountant), Carol(CFO) and Alice(CEO) into the owner-permission of her account. Bob’s signature weight is 2, Carol’s signature weight is 2, Alice’s signature weight is 5. Owner-permission’s signature weight threshold is 3. Alice’s signature weight is bigger than the threshold(5 > 3), so her only signature is sufficient to make transactions. Bob’s signature weight is smaller than the threshold(2 < 3), to make a transaction, Bob needs Carol’s or Alice’s signature if Carol approves, the total signature weight is 2+2 > 3, so the transaction can be executed.

Alice has many TRX assets. One day, misfortune has come, Alice is dead due to an accident. She is the only one who holds the private key of her account, so her assets will stay in that account forever, nobody can get it. (Current Scenario) Alice has many TRX assets. She creates an active-permission for her account, adds her husband and son’s addresses into the active-permission, and give the active-permission authority to operate her account. So after Alice no longer exists, her family members can still operate her account.

Alice is running a company, she creates an account as her business account. Alice creates an active-permission and adds Bob(Accountant), Carol(CFO) and Alice(CEO) into the active-permission of the account. Alice gives the active-permission authority to operate her business account. One day, Bob resigns. To keep Alice’s account safe, Alice can remove Bob’s account from the active-permission, then Bob can not operate her account anymore.

Alice has a witness account, if she wants to deploy a node but doesn’t know how to deploy, she needs to provide the account’s private key to the program administrator. (Current Scenario) Alice can assign witness-permission to the administrator. Since the administrator only has the producing-block permission, there is no TRX transfer permission, and even if the private key of the administrator on the server is compromised, TRX will not be lost.


Let’s see the protocol design of multi-signature first. Related structs in protocol include Account, Permission, Key, Transaction.


message Account {    ...    Permission owner_permission = 31;    Permission witness_permission = 32;    repeated Permission active_permission = 33;}

There are 3 different roles of permission: owner, witness and active. Owner permission has the right to execute all the contracts, witness permission is for SR, active permission contains a set of contracts selected execution permissions. Related attributes are added to the account: owner_permission、witness_permission and active_permission. active_permission is a list, the length must <= 8.


message Permission {    enum PermissionType {        Owner = 0;        Witness = 1;        Active = 2;    }    PermissionType type = 1; // enum permission type, {0,1,2}    int32 id = 2; // Generated by system. Owner id=0, Witness id=1, Active id increases from 2. Specifying using which permission to execute a contract by setting id. For instance, using owner permission, set id=0, {0,1,2,3,4,5,6,7,8,9}    string permission_name = 3;  // Permission name, 32 bytes length limit    int64 threshold = 4;  // The threshold of the signature weight    int32 parent_id = 5;  // deprecated, 0    bytes operations = 6;  // 32 bytes (256 bit), each bit corresponds whether has the execution permission of each type of contract    repeated Key keys = 7;// The list of accounts and weights that own the permission, the length must <= 5.}

Each bit of struct member `operations`, 1 means true, 0 means not, support up to 256 different type of contract; index refers to the definition of Transaction.ContractType (see below).

For instance, operations=0x0100…00(hex) or 100…0(binary), only the first bit is 1, the id of AccountCreateContract is 0, means this permission only owns the execution permission of AccountCreateContract. If the operations=0x7f ff 1f c0 03 3e 03 …(hex) or 11111110 11111111 11111000 00000011 11000000 01111100 11000000 …(binary), the 47th bit of operations is 0, it means it doesn’t support the execution of `AccountPermissionUpdateContract`, as the ContractType of `AccountPermissionUpdateContract` is 46 (start from 0) listed below.

All the hex byte sequences of operations are ordered in little-endian coding, but for each byte, it’s ordered in big-endian for binary bits. For the above example, the first byte is 7f, its corresponding binary coding is 11111110 ; the third byte is 1f, its corresponding binary coding is 11111000.


message Key {    bytes address = 1;// the account address    int64 weight = 2;// the signature weight}


message Transaction {    message Contract {        enum ContractType {            AccountCreateContract = 0;            ...            AccountPermissionUpdateContract = 46;            ...
} ContractType type = 1; ... int32 Permission_id = 5;// Permission_id in Transaction corresponds to id in Permission.}

Owner Permission:

Owner permission is the top permission of an account. It is used to control account ownership, adjust permission structure. Owner Permission has the right to execute all the contracts.

Owner permission’s features:

  1. The account that has owner permission can change the owner permission
  2. When owner permission is null, the default owner of the account owns the owner permission
  3. When you create a new account, the address will be insert into owner permission automatically, default weight is 1, keys field only contains this address and also weight is 1.
  4. If a permissionId is not specified when a contract is executed, using owner permission by default.

Witness Permission:

Super representatives can use this permission to manage block producing. Only witness account has this permission.

Usage scenario example:

A super representative deploys a witness node on cloud server. In order to keep the account on the cloud server safe, you can only give the block producing permission to the account you put on cloud server. Because this account only owns block producing permission, no TRX transfer permission, so even if the account on the cloud server is leaked, the TRX will not be lost.

Witness node configuration:

  1. if no witness permission is used, no need to configure
  2. if witness permission is used, need to reconfigure:
#config.conf// Optional.The default is empty.// It is used when the witness account has set the witnessPermission.// When it is not empty, the localWitnessAccountAddress represents the address of the witness account,// and the localwitness is configured with the private key of the witnessPermissionAddress in the witness account.// When it is empty,the localwitness is configured with the private key of the witness account.//localWitnessAccountAddress =localwitness = [f4df789d3210ac881cb900464dd30409453044d2777060a0c391cbdf4c6a4f57]

Active Permission:

Active permission is composed of a set of contract execution permission, like creating an account, transfer function, etc. Active permission’s features:

  1. the account owns owner permission can change active permission
  2. the account owns the execution permission of AccountPermissionUpdateContract can also change active permission
  3. 8 permissions at most
  4. permissionId increases from 2 automatically
  5. when a new account is created, an active permission will be created automatically, and the address will be inserted into it, default weight is 1, keys field only contains this address and weight is 1


  1. Using AccountPermissionUpdateContract costs 100TRX
  2. If a transaction contains 2 or more signatures, it charges an extra 1 TRX besides the transaction fee
  3. The fee can be modified by proposing

Change Permission:

If the account has `AccountPermissionUpdateContract` permission, it can change the permissions by the following steps:

  1. call `getaccount` to query the account, get the original permission
  2. change permission with `AccountPermissionUpdateContract`


http://{host}:{port}/wallet/accountpermissionupdate{"owner_address": "41ffa9466d5bf6bb6b7e4ab6ef2b1cb9f1f41f9700","owner": {"type": 0,"id": 0,"permission_name": "owner","threshold": 2,"keys": [{"address": "41ffa9466d5bf6bb6b7e4ab6ef2b1cb9f1f41f9700","weight": 1},{"address": "{account_1}","weight": 1},{"address": "{account_2}","weight": 1}]},"witness": {"type": 1,"id": 1,"permission_name": "witness","threshold": 1,"keys": [{"address": "41F08012B4881C320EB40B80F1228731898824E09D","weight": 1}]},"actives": [{"type": 2,"id": 2,"permission_name": "active0","threshold": 3,"operations": "7fff1fc0037e0000000000000000000000000000000000000000000000000000","keys": [{"address": "{account_3}","weight": 1},{"address": "{account_4}","weight": 1},{"address": "{account_5}","weight": 1}]},{"type": 2,"id": 3,"permission_name": "active1","threshold": 3,"operations": "7fff1fc0037e0000000000000000000000000000000000000000000000000000","keys": [{"address": "{account_6}","weight": 1},{"address": "{account_7}","weight": 1},{"address": "{account_8}","weight": 1}

The account 41ffa9466d5bf6bb6b7e4ab6ef2b1cb9f1f41f9700 gives the owner access to itself and account_1, account_2 with id 0;

give witness access to 41F08012B4881C320EB40B80F1228731898824E09D with id 1;

gives active access to account_3 , account_4, account_5 with id 2;

give active access to account_6, account_7, account_8 with id 3.

Active access will need signatures from both accounts in order to take effect. If the account is not a witness, it’s not necessary to set witness_permission, otherwise an error will occur.

3. build and sign the transaction

4. send transaction to node

How to make Multi-signature with http API:

  1. Assuming there are 5 accounts: owner, active1, active2, active3, receiver.
    We suppose account ‘owner’ has 5000 TRX and plans to send 1000 TRX to ’receiver, this transaction will be successful only if obtaining at least 2 signatures from the other 3 account owners.

2. ‘owner’ creates a transaction to update account permission type. is the ip and http service port of a test node.

# curl -X POST{"owner_address" : "41AF498B43EE098B26926798CFEAE1AB1154EF4430","owner": {"type": 0,"id": 0,"permission_name": "owner","threshold": 1,"keys": [{"address": "41AF498B43EE098B26926798CFEAE1AB1154EF4430","weight": 1}]},"actives": [{"type": 2,"id": 2,"permission_name": "active1","threshold": 2,"operations": "7fff1fc0033e0000000000000000000000000000000000000000000000000000","keys": [{"address": "41A6D58DCB0E0FC0C3FE23CC405D5BD7979E9016FB","weight": 1},{"address": "41F04DC975557388CD5D5FBCAAA706D76AAD415E59","weight": 1},{"address": "41CC187927EB7D648D779FE363F7915DDCFBF2212B","weight": 1}]}]}

gets response in json type, named ${result_2}

3. ‘owner’ signs the transaction with his private key.

# curl -X POST{"transaction" :${result_2} ,"privateKey": "1bb32958909299db452d3c9bbfd15fd745160d63e4985357874ee57708435a00"}

gets response in json type, named ${result_3},

Note: Using this api may have your private key leaked.

4. ‘owner’ broadcasts this transaction

# curl -X POST${result_3}

5. anyone creates a transfer transaction from ‘owner’ to ‘receiver’ and assign 2 to permission_id.

# curl -X POST{"owner_address": "41AF498B43EE098B26926798CFEAE1AB1154EF4430","to_address": "41CA6E0F4BC55CFEC286B3E2F3CB45CBAC87792B78","amount": 1000,"Permission_id" : 2}

gets response in json type, named ${result_5} and sends ${result_5} to ‘active1’ in String type.

6. user ‘active1’ signs the receiving transaction with his private key.

# curl -X POST{"transaction" : ${result_5},"privateKey": "1bb32958909299db452d3c9bbfd15fd745160d63e4985357874ee57708435a11"}

gets response in json type, named ${result_6} and sends ${result_6} to ‘active2’ in String type.

Note: Using this api may have your private key leaked.

7. user ‘active2’ signs the receiving transaction with his private key.

curl -X POST{"transaction" : ${result_6},"privateKey": "1bb32958909299db452d3c9bbfd15fd745160d63e4985357874ee57708435a22"}

Note: Using this api may have your private key leaked.

8. user ‘active2’ broadcasts the transaction

# curl -X POST${result_7}

9. anyone can query the receiver’s account’s balance to verify the execution of the transaction

# curl -X POST{"address": "41CA6E0F4BC55CFEC286B3E2F3CB45CBAC87792B78"}


By providing the multi-signature operation permission, it can empower the account permission control more flexibility and satisfy the different demands of account management.


For more information