Skip to main content

Creating accounts

You can create or import accounts into the Octez client just like you do so in wallet applications.

Octez keeps a local list of aliases for addresses, including user accounts, smart contracts, and Smart Rollups. You can list the aliases that the Octez client is aware of by running the command octez-client list known addresses. When you run transactions with Octez, you can use the alias in place of the account address.

Creating accounts

To create an account, run this command, replacing local_account with a local name for the new account:

octez-client gen keys local_account

You can see the address of the account by running this command:

octez-client show address local_account

To print the private key for the address, add the --show-secret argument.

The account address (technically the hash of the public key) starts with tz1, tz2, tz3, or tz4 depending on the options that you use when you create the account. For command reference, see Command Line Interface in the Octez and protocol documentation.

You can use this address to send tez to this account, such as from a faucet if you are using a testnet. See Testing on testnets.

Importing pre-existing accounts

If you already have a Tezos account, you can import your private key to use the account in Octez:

  1. Export the private key from your wallet application, being careful not to expose it to anyone.

  2. Run this command, replacing the placeholder <ALIAS> with a local alias for the account and the placeholder <PRIVATE_KEY> with the private key:

    octez-client import secret key <ALIAS> unencrypted:<PRIVATE_KEY>

Now you can use the alias in place of the address when you send transactions with Octez.

Exporting accounts

To export an account and use it in another wallet, you can make the Octez client print its secret key by adding the -S switch to the octez-client show address command, as in this example:

octez-client show address local_account -S

There is no way to export all of the addresses in the Octez client at once, but you can print all of the accounts in the Octez client with the command octez-client list known addresses. You can also see the keys in the file ~/.tezos-client/secret_keys.

Revealing accounts

User accounts are unrevealed until they make a transaction. To reveal an account, send any transaction from it, such as calling a smart contract or sending tez to any account, including itself. Unrevealed accounts can receive and store tez, but doing so does not reveal them. An account must have some tez to be revealed.

You can also use the dedicated reveal operation to reveal an account. You can use the Octez client to create this reveal operation by passing the account alias to the reveal key for command, as in this example:

octez-client reveal key for local_account

You can tell if an account is revealed by calling the /chains/main/blocks/<block_id>/context/contracts/<contract_id> RPC endpoint, as in this example:

octez-client rpc get /chains/main/blocks/head/context/contracts/tz1QCVQinE8iVj1H2fckqx6oiM85CNJSK9Sx

The response includes the balance, delegate, and counter for the account and a Boolean field named revealed which is true if it has been revealed or false if it has not:

{ "balance": "9104058003",
"delegate": "tz1NNT9EERmcKekRq2vdv6e8TL3WQpY8AXSF",
"counter": "128420",
"revealed": true
}

Delegating accounts

An account can delegate to another account, usually a baker account. As described in Bakers, delegating your account to a baker account puts your tez toward the voting power of the baker account. Delegating is also a prerequisite for staking. For more information about staking, see Staking and Managing tez.

You can delegate using the staking site as described in Staking, or you can delegate your account by passing the account and the delegate account to the Octez client set delegate for command, as in this example, which uses <ALIAS> as the alias for your account and <BAKER> as the address or alias to delegate to:

octez-client set delegate for <ALIAS> to <BAKER>

To delegate to an account, the target account must be registered as a delegate.

Registering as a delegate

To register as a delegate and allow other accounts to delegate to you, pass the account alias to the Octez client register key command, as in this example:

octez-client register key <ALIAS> as delegate

For baking delegation scenarios, including registering with a consensus key, see Run a Tezos node in 5 steps.

Multi-signature accounts

As described in Multi-signature accounts, multi-signature accounts (multisigs) require multiple other accounts to authorize operations before running them.

When you create a multi-signature account, you determine how access is shared among the participant accounts. You can configure a multi-signature account to be split among any number of participant accounts and to require all or only some of their signatures to authorize an operation. In general, multisig accounts are referred to as using one of these schemes:

  • Signature aggregation (aka N-of-N scheme): All N participants to the multisig account must sign every operation.
  • Threshold signature (M-of-N scheme): A threshold number of M participants out of the total of N members is required to sign each operation.

In either case, there must be at least 2 participants (N >= 2) and at least 2 of them must be required to sign an operation (M >= 2).

note

Built-in multi-signature accounts were introduced in the Seoul protocol and require accounts that start with tz4, which are created with the BLS signature scheme. If you created a tz4 account prior to Seoul, you must re-reveal them after Seoul becomes active.

Multi-signature accounts require version 23 or later of the Octez client.

Creating multi-signature accounts

There are two ways to create a multi-signature account:

For a walkthrough, see Staking and baking with native multisig accounts.

Creating a multisig account from existing accounts

Creating a multisig account in this way requires 2 or more existing tz4 accounts. You use the public keys for these accounts to generate the public key and tz4 address of the multisig account and the proof of possession, which allows participants to create operations on behalf of the multisig account.

note

Creating a multisig account in this way always results in an N-of-N scheme, in which every participant account must sign every operation. To create a multisig account with an M-of-N scheme, use the method described in Creating a multisig account and new participant accounts.

  1. If you don't already have the participant accounts, create them with the gen keys command as usual, but pass the -s bls argument to use the BLS scheme, which creates a tz4 account:

    octez-client gen keys participant_1 -s bls
  2. Generate a proof of possession (PoP) for each participant account with the create bls proof for command, as in this example:

    octez-client create bls proof for participant_1

    The response is the PoP for the account. You can also see the PoP in the metadata for the reveal operation for the account.

  3. Aggregate the accounts into a multisig account by passing the public keys and PoPs to the aggregate bls public keys, as in this example:

    octez-client aggregate bls public keys '[
    {
    "public_key": "<PARTICIPANT_1_PK>",
    "proof": "<PARTICIPANT_1_POP>"
    },
    {
    "public_key": "<PARTICIPANT_2_PK>",
    "proof": "<PARTICIPANT_2_POP>"
    },
    {
    "public_key": "<PARTICIPANT_3_PK>",
    "proof": "<PARTICIPANT_3_POP>"
    }
    ]'

    This example uses placeholders such as <PARTICIPANT_1_PK> and <PARTICIPANT_1_POP> for the public key (not the address) and PoP of each of the participant accounts.

    The response includes the public key and public key hash (address) of the new multisig account.

  4. Generate the combined PoP for the multisig account:

    1. Generate a PoP fragment for each participant account by passing the public key to the create bls proof for command for each account. This example uses <MULTISIG_PK> for the public key of the multisig account:

      octez-client create bls proof for participant_1 --override-public-key <MULTISIG_PK>
    2. Combine the PoP fragments to the PoP for the multisig accounts by passing the PoP fragments to the aggregate bls proofs, as in this example:

      octez-client aggregate bls proofs '{
      "public_key": "<MULTISIG_PK>",
      "proofs": [
      "<PARTICIPANT_1_POP_FRAGMENT>",
      "<PARTICIPANT_2_POP_FRAGMENT>",
      "<PARTICIPANT_3_POP_FRAGMENT>"
      ]
      }'

      The response is the aggregated proof for the multisig account, which you will need for each operation from the account.

      The order of the PoPs in this command is not important.

  5. Reveal the public key of the multisig account by aggregating the signatures of the participant accounts and injecting a reveal operation:

    1. Send some tez to the multisig account, because a user account with no tez can't be revealed.

    2. Get the counter for the multisig account by passing its address to the /counter RPC endpoint, as in this example, which uses <MULTISIG_ADDRESS> as a placeholder for the address of the multisig account:

      octez-client rpc get chains/main/blocks/head/context/contracts/<MULTISIG_ADDRESS>/counter
    3. Get the hash of a recent block to use as the starting point for the operation:

      octez-client rpc get chains/main/blocks/head~2/hash
    4. Encode the reveal operation to binary by passing it to the octez-codec program. This example uses the placeholders <COUNTER_PLUS_1> for the current counter plus one and uses <BRANCH> as the hash of a recent block:

      octez-codec encode 023-PtSeouLo.operation.unsigned from '{
      "branch": "<BRANCH>",
      "contents":
      [ { "kind": "reveal",
      "source": "<MULTISIG_ADDRESS>", "fee": "1450",
      "counter": "<COUNTER_PLUS_1>", "gas_limit": "3250", "storage_limit": "0",
      "public_key": "<MULTISIG_PK>",
      "proof": "<MULTISIG_PROOF>" } ] }'

      This command encodes the values for the operation with the octez-codec program, based on the Seoul protocol. You can replace 023-PtSeouLo.operation.unsigned with the schema for the protocol that you want to use; see Encodings in the Octez and protocol documentation.

      The response is the bytecode-encoded operation.

    5. As the participant accounts, sign the encoded operation. This example signs the bytecode <ENCODED_OPERATION> as the account with the local alias participant_1:

      octez-client sign bytes "0x03<ENCODED_OPERATION>" for participant_1

      Note that in this command, the encoded operation is prefixed with the code 0x03.

      The response is the account's signature for the operation.

    6. When you have signatures from all of the participant accounts, combine them into a single aggregated signature. This example uses placeholders such as <SIGNATURE_1> for the signatures from each account. The order of the signatures is not important.

      octez-client aggregate bls signatures '{
      "public_key": "<MULTISIG_PK>",
      "message": "03<ENCODED_OPERATION>",
      "signature_shares": [
      "<SIGNATURE_1>",
      "<SIGNATURE_2>",
      "<SIGNATURE_3>"
      ]
      }'

      The response is the combined signature for the operation.

    7. Sign the operation by running this command, which uses the same JSON parameter as the command to generate the operation with the addition of the signature field:

      octez-codec encode 023-PtSeouLo.operation from '{
      "branch": "<BRANCH>",
      "contents":
      [ { "kind": "reveal",
      "source": "<MULTISIG_ADDRESS>", "fee": "1450",
      "counter": "<COUNTER_PLUS_1>", "gas_limit": "3250", "storage_limit": "0",
      "public_key": "<MULTISIG_PK>",
      "proof": "<MULTISIG_PROOF>" } ],
      "signature": "<COMBINED_SIGNATURE>" }'

      The value of the signature field, represented by the placeholder <COMBINED_SIGNATURE>, is the output of the previous command.

      The response is the bytecode of the signed operation.

    8. Inject the signed operation from the previous step by passing it to the /injection/operation RPC endpoint, as in this example:

      octez-client rpc post /injection/operation with '"<SIGNED_OPERATION>"'

      The response is the hash of the operation.

    You can use the same process for signing and injecting other transactions from the multisig account, as described in Signing operations with multi-signature accounts.

Now the multisig account is active and the participants can co-sign transactions to submit transactions on its behalf.

Creating a multisig account and new participant accounts

When you create a multi-signature account with this method, you create the account and then split it into multiple other new accounts. Follow these steps:

  1. Create the account with the gen keys command as usual, but pass the -s bls argument to use the BLS scheme, which creates a tz4 account:

    octez-client gen keys my_multisig -s bls
  2. Get the secret key of the account with the show address command and the --show-secret argument:

    octez-client show address my_multisig --show-secret
  3. Pass the secret key of the account to the share bls secret key command and specify how many participant accounts to create and how many of these accounts must authorize operations. For example, this command creates 3 participant accounts, 2 of which must authorize each operation:

    octez-client share bls secret key <SECRET_KEY> between 3 shares with threshold 2

    The response includes the proof for the multi-sig account and the secret keys and IDs for the participant accounts, as in this example:

    { "public_key":
    "<MULTISIG_PK>",
    "public_key_hash": "<MULTISIG_ADDRESS>",
    "proof":
    "<MULTISIG_PROOF>",
    "secret_shares":
    [ { "id": 1,
    "secret_key":
    "<SECRET_1>" },
    { "id": 2,
    "secret_key":
    "<SECRET_2>" },
    { "id": 3,
    "secret_key":
    "<SECRET_3>" } ] }
  4. Save the proof and information about the participant accounts.

    note

    Be sure to save the IDs of the participant accounts so you can link the IDs with the accounts themselves. In later transactions, you must link the participant signatures with their IDs.

  5. Use the secret keys provided in the response to import new accounts with the Octez client. You can import the accounts yourself or distribute the keys to other people. For example, this command imports the account with the placeholder secret key <SECRET_1> and gives it the local alias participant_1:

    octez-client import secret key participant_1 unencrypted:<SECRET_1>
  6. Destroy the secret key of the multisig account because it is no longer needed. For example, this Octez client command removes an account named my_multisig, including the -f argument to delete the private key:

    octez-client forget address my_multisig -f
    important

    Whoever has the secret key of the multisig account can sign operations for it independently, getting around the authorization of the participants. For security, after you have imported the participant accounts, ensure that the secret key for the multisig account is destroyed.

  7. Optional: To keep track of the account's address and public key, add it back as a local alias by running this command, where <MULTISIG_PK> is the public key of the multisig account:

    octez-client import public key my_multisig unencrypted:<MULTISIG_PK>

    Now you can get the address of the account with the command octez-client show address multisig_staker and use its alias locally, but you don't have its private key.

  8. Reveal the public key of the multisig account by aggregating the signatures of the participant accounts and injecting a reveal operation:

    1. Send some tez to the multisig account, because a user account with no tez can't be revealed.

    2. Get the counter for the multisig account by passing its address to the /counter RPC endpoint, as in this example, which uses <MULTISIG_ADDRESS> as a placeholder for the address of the multisig account:

      octez-client rpc get chains/main/blocks/head/context/contracts/<MULTISIG_ADDRESS>/counter
    3. Get the hash of a recent block to use as the starting point for the operation:

      octez-client rpc get chains/main/blocks/head~2/hash
    4. Create the operation by passing the reveal operation to the octez-codec program. This example uses the placeholders <COUNTER_PLUS_1> for the current counter plus one and uses <BRANCH> as the hash of a recent block:

      octez-codec encode 023-PtSeouLo.operation.unsigned from '{
      "branch": "<BRANCH>",
      "contents":
      [ { "kind": "reveal",
      "source": "<MULTISIG_ADDRESS>", "fee": "1450",
      "counter": "<COUNTER_PLUS_1>", "gas_limit": "3250", "storage_limit": "0",
      "public_key": "<MULTISIG_PK>",
      "proof": "<MULTISIG_PROOF>" } ] }'

      The response is the bytecode-encoded operation.

    5. As the participant accounts, sign the encoded operation. This example signs the bytecode <ENCODED_OPERATION> as the account with the local alias participant_1:

      octez-client sign bytes "0x03<ENCODED_OPERATION>" for participant_1

      Note that in this command, the encoded operation is prefixed with the code 0x03.

      The response is the account's signature for the operation.

    6. When you have signatures from enough of the participant accounts, combine them into a single threshold signature. This example uses placeholders such as <SIGNATURE_1> for the signatures from each account:

      octez-client threshold bls signatures '{
      "public_key": "<MULTISIG_PK>",
      "message": "03<ENCODED_OPERATION>",
      "signature_shares": [
      { "id": 1, "signature": "<SIGNATURE_1>"},
      { "id": 2, "signature": "<SIGNATURE_2>"}
      ]
      }'
      note

      Each signature in this command is connected to the ID of the account when you created it with the share bls secret key command. The signature is not valid if these IDs don't match.

      The response is the combined signature for the operation.

    7. Sign the operation by running this command, which uses the same JSON parameter as the command to generate the operation with the addition of the signature field:

      octez-codec encode 023-PtSeouLo.operation from '{
      "branch": "<BRANCH>",
      "contents":
      [ { "kind": "reveal",
      "source": "<MULTISIG_ADDRESS>", "fee": "1450",
      "counter": "<COUNTER_PLUS_1>", "gas_limit": "3250", "storage_limit": "0",
      "public_key": "<MULTISIG_PK>",
      "proof": "<MULTISIG_PROOF>" } ],
      "signature": "<COMBINED_SIGNATURE>" }'

      The response is the bytecode of the signed operation.

    8. Inject the signed operation from the previous step by passing it to the /injection/operation RPC endpoint, as in this example:

      octez-client rpc post /injection/operation with '"<SIGNED_OPERATION>"'

      The response is the hash of the operation.

    You can use the same process for signing and injecting other transactions from the multisig account, as described in Signing operations with multi-signature accounts.

Now the multisig account is active and the participants can co-sign transactions to submit transactions on its behalf.

important

Whoever has the secret key of the multisig account can sign operations for it independently, getting around the authorization of the participants. For security, after you have imported the participant accounts, ensure that the secret key for the multisig account is destroyed.

Signing operations with multi-signature accounts

To sign operations for the multisig account (regardless of which method you used to create it), enough participants must sign the same operation and provide their signatures. Then anyone can aggregate those signatures and submit the operation.

Signing operations for multisig accounts requires multiple steps that must be done within a specified amount of time. In particular, the operation is based on a recent block (referred to as a branch). If this branch is too old when you submit the signed operation, the operation fails. Therefore, you may want to review the following instructions and plan the commands that you need to run so you can complete them in time. You can also automate the process with a program to save time and prevent errors.

  1. Generate the bytes that the participants must sign:

    1. Get the counter for the multisig account by passing its address to the /counter RPC endpoint, as in this example, which uses <MULTISIG_ADDRESS> as a placeholder for the address of the multisig account:

      octez-client rpc get chains/main/blocks/head/context/contracts/<MULTISIG_ADDRESS>/counter
    2. Get the hash of a recent block to use as the starting point (branch) for the operation:

      octez-client rpc get chains/main/blocks/head~2/hash
    3. Encode the operation to binary by passing it to the octez-codec program. For example, this operation transfers 1 tez from the multisig account <MULTISIG_ADDRESS> to the target account <TARGET>. It adds one to the value returned for the multisig account's counter from a previous step as <COUNTER_PLUS_1> and uses <BRANCH> as the hash of a recent block:

      octez-codec encode 023-PtSeouLo.operation.unsigned from '{
      "branch": "<BRANCH>",
      "contents":
      [ { "kind": "transaction",
      "source": "<MULTISIG_ADDRESS>", "fee": "1000",
      "counter": "<COUNTER_PLUS_1>", "gas_limit": "3674", "storage_limit": "0",
      "amount": "1000000",
      "destination": "<TARGET>" } ] }'

      The response is the bytecode-encoded operation.

    4. As the participant accounts, sign the encoded operation. This example signs the bytecode <ENCODED_OPERATION> as the account with the local alias participant_1:

      octez-client sign bytes "0x03<ENCODED_OPERATION>" for participant_1

      Note that in this command, the encoded operation is prefixed with the code 0x03.

      The response is the account's signature for the operation.

    5. When you have the necessary number of signatures from the participant accounts, combine them into a single final signature. The process is different for N-of-N schemes and M-of-N schemes.

      These examples use placeholders like <SIGNATURE_1> for the participant signatures and <MULTISIG_PK> for the public key of the multisig account. Also note that in this command, the encoded operation is prefixed with the code 03, not 0x03 as in the previous command.

      • If you are using an N-of-N scheme (all participants must sign), pass the signatures to the aggregate bls signatures command:

        octez-client aggregate bls signatures '{
        "public_key": "<MULTISIG_PK>",
        "message": "03<ENCODED_OPERATION>",
        "signature_shares": [
        "<SIGNATURE_1>",
        "<SIGNATURE_2>",
        "<SIGNATURE_3>"
        ]
        }'
      • If you are using an M-of-N scheme (a threshold amount of participants must sign), pass the signatures to the threshold bls signatures command:

        octez-client threshold bls signatures '{
        "public_key": "<MULTISIG_PK>",
        "message": "03<ENCODED_OPERATION>",
        "signature_shares": [
        { "id": 1, "signature": "<SIGNATURE_1>"},
        { "id": 2, "signature": "<SIGNATURE_2>"}
        ]
        }'
        note

        Each signature in this command is connected to the ID of the account when you created it with the share bls secret key command. The signature is not valid if these IDs don't match.

      The response is the combined signature for the operation.

    6. Sign the operation by running this command, which uses the same JSON parameter as the command to generate the operation with the addition of the signature field:

      octez-codec encode 023-PtSeouLo.operation from '{
      "branch": "<BRANCH>",
      "contents":
      [ { "kind": "transaction",
      "source": "<MULTISIG_ADDRESS>", "fee": "1000",
      "counter": "<COUNTER_PLUS_1>", "gas_limit": "3674", "storage_limit": "0",
      "amount": "1000000",
      "destination": "<TARGET>" } ],
      "signature": "<COMBINED_SIGNATURE>" }'

      The value of the signature field, represented by the placeholder <COMBINED_SIGNATURE>, is the output of the previous command.

      The response is the bytecode of the signed operation.

    7. Inject the signed operation by sending it to the /injection/operation RPC endpoint, as in this example, which uses <SIGNED_OPERATION> as the signed operation:

      octez-client rpc post /injection/operation with '"<SIGNED_OPERATION>"'

      If the injection is successful, the RPC endpoint returns the hash of the operation.

      If the branch has expired, the endpoint returns an error saying that the operation is branched on a block that is too old or unknown.

    8. Verify that the operation succeeded by looking it up on a block explorer or by passing the hash to the octez-client get receipt for command.

You can send many different kinds of operations in this way. For example, this command stakes 100 tez on behalf of the multisig accounts:

octez-codec encode 023-PtSeouLo.operation.unsigned from '{
"branch": "<BRANCH>",
"contents":
[ { "kind": "transaction",
"source": "<MULTISIG_ADDRESS>", "fee": "808",
"counter": "<COUNTER_PLUS_1>", "gas_limit": "5134", "storage_limit": "0",
"amount": "100000000",
"destination": "<MULTISIG_ADDRESS>",
"parameters":
{ "entrypoint": "stake", "value": { "prim": "Unit" } } } ] }'

You can also bundle transactions within the contents field of the JSON data. For example, this command reveals the account and sets its delegation to the account represented by the placeholder <DELEGATE>:

octez-codec encode 023-PtSeouLo.operation.unsigned from '{
"branch": "<BRANCH>",
"contents":
[ { "kind": "reveal",
"source": "<MULTISIG_ADDRESS>", "fee": "735",
"counter": "<COUNTER_PLUS_1>", "gas_limit": "3251", "storage_limit": "0",
"public_key": "<MULTISIG_PK>",
"proof": "<MULTISIG_PROOF>" },
{ "kind": "delegation",
"source": "<MULTISIG_ADDRESS>", "fee": "448",
"counter": "<COUNTER_PLUS_2>", "gas_limit": "1673", "storage_limit": "0",
"delegate": "<DELEGATE>" } ] }'