# Multi-signature smart contracts¶

A multi-signed account, or multisig for short, is a way to share the ownership of an address (and of the associated balance) between several participants.

To act on a multisig, a fraction of the participants must agree on the action by signing it with their private keys. The minimal number of participants that need to agree for the action to be approved is called the multisig threshold.

On Tezos, a way to run a multisig is by using a smart contract. Such a multisig contract has built-in support in the tezos-client and has been formally verified using the Mi-Cho-Coq framework.

## Interacting with a multisig contract using tezos-client¶

The recommended way to create and use a multisig contract is via the tezos-client built-in commands for the multisig contract. The command tezos-client man multisig gives a complete list of multisig-related commands with details about the syntax of each command.

### Originating a new multisig contract¶

To originate a new generic multisig contract, use the tezos-client deploy multisig command. It is similar to tezos-client originate contract with the following differences:

• no script is given because the script of the generic multisig contract is fixed

• instead of giving the initial storage with the --init option, the threshold and the public keys of the participants are given on the command line.

For example, the following commands can be used to generate three pairs of keys named alice, bob, and charlie and originate a multisig contract named msig that can be actioned by any two of them; the initial balance of this contract and of each of the signers is ꜩ100 generously offered by the first bootstrap account:

$tezos-client gen keys alice$ tezos-client gen keys bob
$tezos-client gen keys charlie$ tezos-client transfer 100 from bootstrap1 to alice --burn-cap 1
$tezos-client transfer 100 from bootstrap1 to bob --burn-cap 1$ tezos-client transfer 100 from bootstrap1 to charlie --burn-cap 1
$tezos-client deploy multisig msig transferring 100 from bootstrap1 with threshold 2 on public keys alice bob charlie --burn-cap 1  ### Preparing a transaction¶ The tezos-client prepare multisig transaction commands are used to obtain the byte sequence corresponding to a possible action and that needs to be signed. To avoid writing Michelson lambdas, special cases for a single transfer or delegate change have their own commands. By default the tezos-client prepare multisig transaction commands display not only the byte sequence to sign but also a cryptographic hash (this can be useful when signing with a hardware signer), the threshold and the participant public keys. To obtain the byte sequence only, these commands accept a --bytes-only option. For example, if Alice and Charlie want to send ꜩ10 from the multisig to Bob they will need to sign a transaction. They can call $ tezos-client prepare multisig transaction on msig transferring 10 to bob


This command will give them the byte sequence they need to sign, its cryptographic hash, the threshold (which is 2 in this case), and the public keys of Alice, Bob, and Charlie.

### Signing an action¶

There are two equivalent ways to sign an action with tezos-client:

• preparing the action with one of the tezos-client prepare multisig transaction commands and then signing it using the tezos-client sign bytes command,

• or directly using one of the tezos-client sign multisig transaction commands that combine these two steps.

For example, Alice can sign the transfer to Bob using

$TO_SIGN=$(tezos-client prepare multisig transaction on msig transferring 10 to bob --bytes-only)


## Supported versions of the multisig contract¶

Two main versions of the multisig contract are supported by tezos-client. They are called the generic multisig contract and the legacy multisig contract.

### The generic multisig contract¶

The generic multisig contract is the multisig contract that is currently recommended. It has the following features:

• it can receive tokens from unauthenticated sources on its default entrypoint of type unit

• the possible authenticated actions on the contract are:

• atomically execute an arbitrary list of operations (of type lambda unit (list operation) in Michelson)

• update the contract storage to change both the threshold and the participant public keys

### The legacy multisig contract¶

The tezos-client also supports a legacy version of the multisig contract which has the following limitations:

• it cannot receive tokens from unauthenticated sources, sending tokens to the contract is only possible as a side effect of an authenticated action

• the possible authenticated actions on the contract are:

• transfer without parameter to an implicit account or to a smart contract with an entrypoint of type unit

• set the delegate of the contract

• remove the delegate of the contract

• update the contract storage to change both the threshold and the participant public keys

In particular, the legacy multisig contract does not support executing several operations atomically, calling smart contracts with parameters, and originating new contracts. In contrast, all the features of the legacy multisig contract are supported by the generic multisig contract.

### Listing supported hashes¶

For security reasons, tezos-client will not interact with unknown scripts even if their interface matches one of the supported multisig contracts. To check if a script is one of the supported ones, it stores a list of script hashes that can be printed by tezos-client show supported multisig hashes. The script originated by the tezos-client deploy multisig command is always one of the supported multisig contracts.

## Interacting with a multisig contract directly¶

The following subsections describe in detail the low-level API of a built-in multisig contract, allowing one to originate and use in situations where tezos-client cannot be used e.g., when interacting with the chain from a web browser or in a mobile application. In particular, this interface is typically useful when developing multisig support in another Tezos wallet.

### Anti-replay protection¶

A replay attack consists in authenticating as someone else by reusing a signature emitted in a different context. Examples of replay attacks include reusing a signature sent in a previous transaction, to another multisig contract, or to the same contract on another chain.

To protect against replay attack, signed data of a multisig contract needs to contain not only the action to perform but also:

• the address of the multisig contract to avoid replaying signatures meant for another multisig contract,

• the chain identifier of the current chain to avoid replaying signatures between the test chain forked during the testing period of the voting procedure and the main chain,

• an always-increasing anti-replay counter to avoid replaying past transactions on the same multisig contract.

The anti-replay counter is stored in the multisig contract storage and incremented at each successful call of the multisig contract.

### Multisig contract storage¶

Both the generic and the legacy multisig contracts have a storage of type (pair (nat %stored_counter) (pair (nat %threshold) (list %keys key))) so the storage of the multisig contract is of the form Pair <stored_counter> (Pair <threshold> { <first_public_key>; <second_public_key>; ...; <last_public_key> }) where <stored_counter> and <threshold> are Micheline integers representing respectively the anti-replay counter and the threshold and each public key is either a Micheline byte sequence or a Micheline string depending on the mode used to unparse the storage.

### Multisig contract actions¶

The type of actions for the generic multisig is (or :action (lambda %operation unit (list operation)) (pair %change_keys (nat %threshold) (list %keys key))) so a valid action is either of the form Left {<code>} where code is of type lambda unit (list operation) for executing the given lambda and sending the produced operations or Right (Pair <new_threshold> {<new_first_public_key>; ...; <new_last_public_key>}) for changing the threshold and participant public keys.

The type of actions for the legacy multisig is (or :action (pair :transfer (mutez %amount) (contract %dest unit)) (or (option %delegate key_hash) (pair %change_keys (nat %threshold) (list %keys key)))) so a valid action is either of the form Left (Pair <amount> <destination>) for a transfer, Right (Left None) for withdrawing the delegate, Right (Left (Some <new_delegate>)) for changing the delegate, or Right (Right (Pair <new_threshold> {<new_first_public_key>; ...; <new_last_public_key>})) for changing the threshold and participant public keys.

### Multisig contract sign data¶

The data to sign for a given action is the binary serialisation (using the PACK Michelson instruction) of an expression of type pair (pair chain_id address) (pair :payload (nat %counter) <action>) where the <chain_id> is the chain id of the current chain as returned by the CHAIN_ID instruction, the address is the one of the multisig contract as returned by SELF; ADDRESS, the nat counter must match exactly the stored counter.

### Multisig contract parameter¶

The generic contract has two entrypoints:

• default of type unit used to receive tokens from unauthenticated sources

• main of type pair (pair :payload (nat %counter) <action>) (list %sigs (option signature)) used to perform a multi-signed action.

The legacy contract has only one entrypoint that is unnamed and whose type corresponds to the second above.

The nat counter must exactly match the stored counter and the list of optional signatures must be of the same length and given in the same order as the stored public keys; None can be used to skip a signature, the number of provided signatures must be greater or equal to the stored threshold.

## Formal verification¶

See here for a formal specification and a correctness proof of the generic multisig script written in Coq using the Mi-Cho-Coq framework.