Account Keys

On this page

Keyring #

Create, import, export and delete keys using the CLI keyring {synopsis}

The keyring holds the private/public keypairs used to interact with the node. For instance, a validator key needs to be set up before running the node, so that blocks can be correctly signed. The private key can be stored in different locations, called “backends”, such as a file or the operating system’s own key storage.

Add keys#

You can use the following commands for help with the keys command and for more information about a particular subcommand, respectively:

ICPlazad keys
ICPlazad keys [command] --help

To create a new key in the keyring, run the add subcommand with a <key_name> argument. You will have to provide a password for the newly generated key. This key will be used in the next section.

ICPlazad keys add mykey

# Put the generated address in a variable for later use.
MY_VALIDATOR_ADDRESS=$(ICPlazad keys show mykey -a)

This command generates a new 24-word mnemonic phrase, persists it to the relevant backend, and outputs information about the keypair. If this keypair will be used to hold value-bearing tokens, be sure to write down the mnemonic phrase somewhere safe!

By default, the keyring generates a eth_secp256k1 key. The keyring also supports ed25519 keys, which may be created by passing the --algo flag. A keyring can of course hold both types of keys simultaneously.

:::tip Note: The Ethereum address associated with a public key can be derived by taking the full Ethereum public key of type eth_secp256k1, computing the Keccak-256 hash, and truncating the first twelve bytes. :::

::: warning NOTE: ICPlaza secp256k1 keys are not supported on ICPlaza due to compatibility issues with Ethereum transactions. :::

Keyring Backends#

OS #

::: tip os is the default option since operating system’s default credentials managers are designed to meet users’ most common needs and provide them with a comfortable experience without compromising on security. :::

The os backend relies on operating system-specific defaults to handle key storage securely. Typically, an operating system’s credential sub-system handles password prompts, private keys storage, and user sessions according to the user’s password policies. Here is a list of the most popular operating systems and their respective passwords manager:

GNU/Linux distributions that use GNOME as default desktop environment typically come with Seahorse. Users of KDE based distributions are commonly provided with KDE Wallet Manager. Whilst the former is in fact a libsecret convenient frontend, the latter is a kwallet client.

The recommended backends for headless environments are file and pass.

File #

The file stores the keyring encrypted within the app’s configuration directory. This keyring will request a password each time it is accessed, which may occur multiple times in a single command resulting in repeated password prompts. If using bash scripts to execute commands using the file option you may want to utilize the following format for multiple prompts:

# assuming that KEYPASSWD is set in the environment
yes $KEYPASSWD | ICPlazad keys add me
yes $KEYPASSWD | ICPlazad keys show me
# start ICPlazad with keyring-backend flag
ICPlazad --keyring-backend=file start

::: tip The first time you add a key to an empty keyring, you will be prompted to type the password twice. :::

Password Store #

The pass backend uses the pass utility to manage on-disk encryption of keys’ sensitive data and metadata. Keys are stored inside gpg encrypted files within app-specific directories. pass is available for the most popular UNIX operating systems as well as GNU/Linux distributions. Please refer to its manual page for information on how to download and install it.

::: tip pass uses GnuPG for encryption. gpg automatically invokes the gpg-agent daemon upon execution, which handles the caching of GnuPG credentials. Please refer to gpg-agent man page for more information on how to configure cache parameters such as credentials TTL and passphrase expiration. :::

The password store must be set up prior to first use:

pass init <GPG_KEY_ID>

Replace <GPG_KEY_ID> with your GPG key ID. You can use your personal GPG key or an alternative one you may want to use specifically to encrypt the password store.

KDE Wallet Manager#

The kwallet backend uses KDE Wallet Manager, which comes installed by default on the GNU/Linux distributions that ships KDE as default desktop environment. Please refer to KWallet Handbook for more information.

Testing #

The test backend is a password-less variation of the file backend. Keys are stored unencrypted on disk. This keyring is provided for testing purposes only. Use at your own risk!

::: danger 🚨 DANGER: Never create your mainnet validator keys using a test keying backend. Doing so might result in a loss of funds by making your funds remotely accessible via the eth_sendTransaction JSON-RPC endpoint.

Ref: Security Advisory: Insecurely configured geth can make funds remotely accessible :::

In Memory #

The memory backend stores keys in memory. The keys are immediately deleted after the program has exited.

:::danger IMPORTANT: Provided for testing purposes only. The memory backend is not recommended for use in production environments. Use at your own risk! :::

Multisig #

Learn how to generate, sign and broadcast a transaction using the keyring multisig

A multisig account is an ICPlaza account with a special key that can require more than one signature to sign transactions. This can be useful for increasing the security of the account or for requiring the consent of multiple parties to make transactions. Multisig accounts can be created by specifying:

  • threshold number of signatures required

  • the public keys involved in signing

To sign with a multisig account, the transaction must be signed individually by the different keys specified for the account. Then, the signatures will be combined into a multisignature which can be used to sign the transaction. If fewer than the threshold number of signatures needed are present, the resultant multisignature is considered invalid.

Generate a Multisig key#

ICPlazad keys add --multisig=name1,name2,name3[...] --multisig-threshold=K new_key_name

K is the minimum number of private keys that must have signed the transactions that carry the public key’s address as signer.

The --multisig flag must contain the name of public keys that will be combined into a public key that will be generated and stored as new_key_name in the local database. All names supplied through --multisig must already exist in the local database.

Unless the flag --nosort is set, the order in which the keys are supplied on the command line does not matter, i.e. the following commands generate two identical keys:

ICPlazad keys add --multisig=p1,p2,p3 --multisig-threshold=2 multisig_address
ICPlazad keys add --multisig=p2,p3,p1 --multisig-threshold=2 multisig_address

Multisig addresses can also be generated on-the-fly and printed through the which command:

ICPlazad keys show --multisig-threshold=K name1 name2 name3 [...]

Signing a transaction#

Step 1: Create the multisig key#

Let’s assume that you have test1 and test2 want to make a multisig account with test3.

First import the public keys of test3 into your keyring.

ICPlazad keys add \
    test3 \
    --pubkey=ICPlazapub1addwnpepqgcxazmq6wgt2j4rdfumsfwla0zfk8e5sws3p3zg5dkm9007hmfysxas0u2

Generate the multisig key with 2/3 threshold.

ICPlazad keys add \
    multi \
    --multisig=test1,test2,test3 \
    --multisig-threshold=2

You can see its address and details:

ICPlazad keys show multi

- name: multi
  type: multi
  address: ICPlaza1e0fx0q9meawrcq7fmma9x60gk35lpr4xk3884m
  pubkey: ICPlazapub1ytql0csgqgfzd666axrjzq3mxw59ys6yqcd3ydjvhgs0uzs6kdk5fp4t73gmkl8t6y02yfq7tvfzd666axrjzq3sd69kp5usk492x6nehqjal67ynv0nfqapzrzy3gmdk27la0kjfqfzd666axrjzq6utqt639ka2j3xkncgk65dup06t297ccljmxhvhu3rmk92u3afjuyz9dg9
  mnemonic: ""
  threshold: 0
  pubkeys: []

Let’s add 10 ICTech to the multisig wallet:

ICPlazad tx bank send \
    test1 \
    ICPlaza1e0fx0q9meawrcq7fmma9x60gk35lpr4xk3884m \
    10000000000000000000aICPlaza \
    --chain-id=ICPlaza_9000-4 \
    --gas=auto \
    --fees=1000000aICPlaza \
    --broadcast-mode=block

Step 2: Create the multisig transaction #

We want to send 5 ICTech from our multisig account to ICPlaza1rgjxswhuxhcrhmyxlval0qa70vxwvqn2e0srft.

ICPlazad tx bank send \
    ICPlaza1rgjxswhuxhcrhmyxlval0qa70vxwvqn2e0srft \
    ICPlaza157g6rn6t6k5rl0dl57zha2wx72t633axqyvvwq \
    5000000000000000000aICPlaza \
    --gas=200000 \
    --fees=1000000aICPlaza \
    --chain-id=ICPlaza_9000-4 \
    --generate-only > unsignedTx.json

The file unsignedTx.json contains the unsigned transaction encoded in JSON.

{
  "body": {
    "messages": [
      {
        "@type": "/ICPlaza.bank.v1beta1.MsgSend",
        "from_address": "ICPlaza1rgjxswhuxhcrhmyxlval0qa70vxwvqn2e0srft",
        "to_address": "ICPlaza157g6rn6t6k5rl0dl57zha2wx72t633axqyvvwq",
        "amount": [
          {
            "denom": "aICPlaza",
            "amount": "5000000000000000000"
          }
        ]
      }
    ],
    "memo": "",
    "timeout_height": "0",
    "extension_options": [],
    "non_critical_extension_options": []
  },
  "auth_info": {
    "signer_infos": [],
    "fee": {
      "amount": [
        {
          "denom": "aICPlaza",
          "amount": "1000000"
        }
      ],
      "gas_limit": "200000",
      "payer": "",
      "granter": ""
    }
  },
  "signatures": []
}

Step 3: Sign individually #

Sign with test1 and test2 and create individual signatures.

ICPlazad tx sign \
    unsignedTx.json \
    --multisig=ICPlaza1e0fx0q9meawrcq7fmma9x60gk35lpr4xk3884m \
    --from=test1 \
    --output-document=test1sig.json \
    --chain-id=ICPlaza_9000-4
ICPlazad tx sign \
    unsignedTx.json \
    --multisig=ICPlaza1e0fx0q9meawrcq7fmma9x60gk35lpr4xk3884m \
    --from=test2 \
    --output-document=test2sig.json \
    --chain-id=ICPlaza_9000-4

Step 4: Create multisignature #

Combine signatures to sign transaction.

ICPlazad tx multisign \
    unsignedTx.json \
    multi \
    test1sig.json test2sig.json \
    --output-document=signedTx.json \
    --chain-id=ICPlaza_9000-4

The TX is now signed:

{
  "body": {
    "messages": [
      {
        "@type": "/ICPlaza.bank.v1beta1.MsgSend",
        "from_address": "ICPlaza1rgjxswhuxhcrhmyxlval0qa70vxwvqn2e0srft",
        "to_address": "ICPlaza157g6rn6t6k5rl0dl57zha2wx72t633axqyvvwq",
        "amount": [
          {
            "denom": "aICPlaza",
            "amount": "5000000000000000000"
          }
        ]
      }
    ],
    "memo": "",
    "timeout_height": "0",
    "extension_options": [],
    "non_critical_extension_options": []
  },
  "auth_info": {
    "signer_infos": [
      {
        "public_key": {
          "@type": "/ICPlaza.crypto.multisig.LegacyAminoPubKey",
          "threshold": 2,
          "public_keys": [
            {
              "@type": "/ICPlaza.crypto.secp256k1.PubKey",
              "key": "ApCzSG8k7Tr4aM6e4OJRExN7cNtvH21L9azbh+uRrvt4"
            },
            {
              "@type": "/ICPlaza.crypto.secp256k1.PubKey",
              "key": "Ah91erz8ChNanqLe9ea948rvAiXMCRlR5Ka7EE/c0xUK"
            },
            {
              "@type": "/ICPlaza.crypto.secp256k1.PubKey",
              "key": "A0OjtIUCFJM3AobJ9HJTWKP9RZV2+WPcwVjLgsAidrZ/"
            }
          ]
        },
        "mode_info": {
          "multi": {
            "bitarray": {
              "extra_bits_stored": 3,
              "elems": "wA=="
            },
            "mode_infos": [
              {
                "single": {
                  "mode": "SIGN_MODE_LEGACY_AMINO_JSON"
                }
              },
              {
                "single": {
                  "mode": "SIGN_MODE_LEGACY_AMINO_JSON"
                }
              }
            ]
          }
        },
        "sequence": "1"
      }
    ],
    "fee": {
      "amount": [
        {
          "denom": "aICPlaza",
          "amount": "1000000"
        }
      ],
      "gas_limit": "200000",
      "payer": "",
      "granter": ""
    }
  },
  "signatures": [
    "CkCEeIbeGc+I1ipZuhp/0KhVNnWAv2tTlvgo5x61lzk1KHmLPV38m/YFurrFt5cm5+fqIXrn+FlOjrJuzBhw8ogYCkCawm9mpXsBHk0CFsE5618fVnvScEkfrzW0c2jCcjqV8EPuj3ut74UWzZyQkwtJGxUWtro9EgnGsB7Di1Gzizst"
  ]
}

Step 5: Broadcast transaction #

ICPlazad tx broadcast signedTx.json \
    --chain-id=ICPlaza_9000-4 \
    --broadcast-mode=block

← Digital Wallets

TechnicalConcepts →

Last updated