Skip to content

Use Hardware Ledger via the Aptos CLI

Using a hardware wallet like Ledger is the most secure way to sign transactions on mainnet as your private key never leaves your device.

You will need to do a few steps of configuration for the Aptos CLI and your Ledger device to sign transactions.

  1. Ensure you have the Aptos CLI installed.

    You can install the Aptos CLI by following these steps if you have not done so already.

  2. Ensure you have done the basic setup for your Ledger device.

    You can find those steps on Ledger’s website. For example, here are the set up instructions for the Ledger Nano X.

  3. Plug your Ledger device into your computer.

  4. Install the Aptos App on your Ledger device by following .

  5. Unlock your Ledger device and open the Aptos app.

  6. Create a new Ledger profile in the Aptos CLI

    Terminal window
    aptos init --profile <your-profile> --ledger

    Then follow the terminal prompts like so:

    Configuring for profile <your-profile>
    Choose network from [devnet, testnet, mainnet, local, custom | defaults to devnet]
    No network given, using devnet...
    Please choose an index from the following 5 ledger accounts, or choose an arbitrary index that you want to use:
    [0] Derivation path: m/44'/637'/0'/0'/0' (Address: 59836ba1dd0c845713bdab34346688d6f1dba290dbf677929f2fc20593ba0cfb)
    [1] Derivation path: m/44'/637'/1'/0'/0' (Address: 21563230cf6d69ee72a51d21920430d844ee48235e708edbafbc69708075a86e)
    [2] Derivation path: m/44'/637'/2'/0'/0' (Address: 667446181b3b980ef29f5145a7a2cc34d433fc3ee8c97fc044fd978435f2cb8d)
    [3] Derivation path: m/44'/637'/3'/0'/0' (Address: 2dcf037a9f31d93e202c074229a1b69ea8ee4d2f2d63323476001c65b0ec4f31)
    [4] Derivation path: m/44'/637'/4'/0'/0' (Address: 23c579a9bdde1a59f1c9d36d8d379aeefe7a5997b5b58bd5a5b0c12a4f170431)
    0
    Account 59836ba1dd0c845713bdab34346688d6f1dba290dbf677929f2fc20593ba0cfb has been already found on-chain
    ---
    Aptos CLI is now set up for account 59836ba1dd0c845713bdab34346688d6f1dba290dbf677929f2fc20593ba0cfb as profile <your-profile>! Run `aptos --help` for more information about commands
    {
    "Result": "Success"
    }

    In the example, they chose to use the first ledger account by entering 0 after the aptos init command. You may choose whichever account you want.

    Common errors:

    1. If you see the error Device Not Found, make sure to unlock your Ledger then try this step again.
    2. If you see the error Aptos ledger app is not opened, make sure to open the Aptos app on your Ledger, then try this step again.
  7. Finally, you will need to enable blind signing on your Ledger device by following .

    1. Blind signing allows you to confirm a smart contract interaction you cannot verify through a human-readable language.
    2. This is needed to execute transactions without limitation as some payloads are too big to display.

After doing the initial setup, you can sign transactions by following these steps:

  1. Plug in your ledger.
  2. Unlock it.
  3. Open the Aptos app.
  4. Run the Aptos CLI command which requires a signature.

For example, if you wanted to publish a Move package like the hello_blockchain demo contract you could follow the above steps then run:

Terminal window
aptos move publish --profile <your-ledger-profile-name> --named-addresses hello_blockchain=<your-ledger-profile-name>

You should see a response like:

Terminal window
Compiling, may take a little while to download git dependencies...
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING Examples
package size 1755 bytes
Do you want to submit a transaction for a range of [139600 - 209400] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
{
"Result": {
"transaction_hash": "0xd5a12594f85284cfd5518d547d084030b178ee926fa3d8cbf699cc0596eff538",
"gas_used": 1396,
"gas_unit_price": 100,
"sender": "59836ba1dd0c845713bdab34346688d6f1dba290dbf677929f2fc20593ba0cfb",
"sequence_number": 0,
"success": true,
"timestamp_us": 1689887104333038,
"version": 126445,
"vm_status": "Executed successfully"
}
}

After you have approved publishing this package you will be prompted to sign the transaction on your Ledger device. Once signed, the package will be published to the network!

One error you might run into is Error: Wrong raw transaction length. This means that the transaction or package size was too big for your device to sign. Currently the Aptos Ledger app can only support transactions that are smaller than 20kb. The Ledger Nano S device has less memory than that, which is why it is more likely to produce this error.

If you have an active account that is not secured using a hardware wallet, then you may wish to rotate the account’s authentication key so that it corresponds to a BIP44 account index private key held on your Ledger.

Alternatively, if you have an account linked with a Ledger hardware wallet that you wish to publish a large package from, you might want to temporarily rotate the account’s authentication key to a hot key to avoid memory issues.

This tutorial will walk you through both scenarios.

  1. Complete the key rotation guide

    Confirm that you have completed the key rotation guide.

  2. Verify your Ledger is ready

    1. Connect and unlock your Ledger.
    2. Check what version of the Aptos app you have: Aptos > About > Version.
    3. If you do not have version 0.6.9 or higher, update it using Ledger Live.
    4. Enable blind signing: Aptos > Settings > Enable Blind Signing.
  3. Start a localnet

    Start a localnet:

    Terminal window
    aptos node run-localnet

    The localnet is ready when it prints out:

    Terminal window
    Applying post startup steps...
    Setup is complete, you can now use the localnet!
  4. Set up localnet hot wallet profile

    Create a private key corresponding to an authentication key, and thus initial account address, that starts with the vanity prefix 0xaaa:

    Terminal window
    aptos key generate \
    --assume-yes \
    --output-file private-key-a \
    --vanity-prefix 0xaaa
    Example output
    Terminal window
    {
    "Result": {
    "PublicKey Path": "private-key-a.pub",
    "PrivateKey Path": "private-key-a",
    "Account Address:": "0xaaac71af5f2a4af4ec2639a15799bf9b945afb061c8bee102b636531c1b00eb5"
    }
    }

    Use the private key to initialize a hot-wallet-1 profile on the localnet:

    Terminal window
    aptos init \
    --assume-yes \
    --network local \
    --private-key-file private-key-a \
    --profile hot-wallet-1
    Example output
    Terminal window
    Configuring for profile hot-wallet-1
    Configuring for network Local
    Using command line argument for private key
    Account 0xaaac71af5f2a4af4ec2639a15799bf9b945afb061c8bee102b636531c1b00eb5 doesn\'t exist, creating it and funding it with 100000000 Octas
    Account 0xaaac71af5f2a4af4ec2639a15799bf9b945afb061c8bee102b636531c1b00eb5 funded successfully
    ---
    Aptos CLI is now set up for account 0xaaac71af5f2a4af4ec2639a15799bf9b945afb061c8bee102b636531c1b00eb5 as profile hot-wallet-1! Run `aptos --help` for more information about commands
    {
    "Result": "Success"
    }
  5. Rotate the hot wallet key

    Rotate the authentication key of the hot wallet to use BIP44 account index 1000 on your Ledger:

    Terminal window
    aptos account rotate-key \
    --assume-yes \
    --new-derivation-index 1000 \
    --profile hot-wallet-1 \
    --save-to-profile ledger-wallet-1000

    Follow the instructions from the CLI prompt:

    Terminal window
    Approve rotation proof challenge signature on your Ledger device
    Example output
    Terminal window
    {
    "Result": {
    "message": "Saved new profile ledger-wallet-1000",
    "transaction": {
    "transaction_hash": "0x1a6df99651ac170bda10cfb9898fa196321d80a928033791b9d2231f77738bb2",
    "gas_used": 448,
    "gas_unit_price": 100,
    "sender": "aaac71af5f2a4af4ec2639a15799bf9b945afb061c8bee102b636531c1b00eb5",
    "sequence_number": 0,
    "success": true,
    "timestamp_us": 1717986382369736,
    "version": 186,
    "vm_status": "Executed successfully"
    }
    }
    }

    Compare the hot-wallet-1 and ledger-wallet-1000 profiles, noting that they have the same account address but different public_key values:

    Terminal window
    aptos config show-profiles --profile hot-wallet-1
    aptos config show-profiles --profile ledger-wallet-1000
    Example output
    Terminal window
    {
    "Result": {
    "hot-wallet-1": {
    "has_private_key": true,
    "public_key": "0xffb1240fd1267207cc3ed2e1b5386e090a9ca2c844d7f9e0077b3d7dd5d5e430",
    "account": "aaa271bca468fb8518f73a732a484b29a1bc296ebcb23f15639d4865a5cebe87",
    "rest_url": "http://localhost:8080",
    "faucet_url": "http://localhost:8081"
    }
    }
    }
    {
    "Result": {
    "ledger-wallet-1000": {
    "has_private_key": false,
    "public_key": "0x20ba83f9b9fdab73b0ace8fda26ce24c98cf55060b72b69cfbd25add6a25d09b",
    "account": "aaa271bca468fb8518f73a732a484b29a1bc296ebcb23f15639d4865a5cebe87",
    "rest_url": "http://localhost:8080",
    "faucet_url": "http://localhost:8081"
    }
    }
    }

    Since the account is no longer secured by the hot private key, delete the private and public key files.

    Now that you have successfully rotated the authentication key of the hot wallet, you can delete the profiles too:

    Terminal window
    aptos config delete-profile --profile hot-wallet-1
    aptos config delete-profile --profile ledger-wallet-1000
    Example output
    Terminal window
    {
    "Result": "Deleted profile hot-wallet-1"
    }
    {
    "Result": "Deleted profile ledger-wallet-1000"
    }
  6. Recover profile

    Since you know that you rotated the authentication key of the hot wallet to the Ledger, and since you used the best practice of a BIP44 account index offset of 1000, you can easily recover the profile using the BIP44 account index alone:

    Terminal window
    aptos init \
    --assume-yes \
    --derivation-index 1000 \
    --network local \
    --profile ledger-wallet-1000-recovered
    Example output
    Terminal window
    Configuring for profile ledger-wallet-1000-recovered
    Configuring for network Local
    Account 0xaaac71af5f2a4af4ec2639a15799bf9b945afb061c8bee102b636531c1b00eb5 has been already found onchain
    ---
    Aptos CLI is now set up for account 0xaaac71af5f2a4af4ec2639a15799bf9b945afb061c8bee102b636531c1b00eb5 as profile ledger-wallet-1000-recovered! Run `aptos --help` for more information about commands
    {
    "Result": "Success"
    }

    Note that this profile corresponds to the specified 0xaaa... vanity account address:

    Terminal window
    aptos config show-profiles --profile ledger-wallet-1000-recovered
    Example output
    Terminal window
    {
    "Result": {
    "ledger-wallet-1000-recovered": {
    "has_private_key": false,
    "public_key": "0x20ba83f9b9fdab73b0ace8fda26ce24c98cf55060b72b69cfbd25add6a25d09b",
    "account": "aaac71af5f2a4af4ec2639a15799bf9b945afb061c8bee102b636531c1b00eb5",
    "rest_url": "http://localhost:8080",
    "faucet_url": "http://localhost:8081"
    }
    }
    }
  7. Rotate to new hot private key

    If you have an account linked with a Ledger hardware wallet that you wish to use for publication of a large package, you’ll be unable to sign the package publication transaction due to the Ledger’s memory limitations. In this case, you’ll want to temporarily rotate to a hot wallet.

    Start by generating a new private key:

    Terminal window
    aptos key generate \
    --assume-yes \
    --output-file private-key-b \
    --vanity-prefix 0xbbb
    Example output
    Terminal window
    {
    "Result": {
    "PublicKey Path": "private-key-b.pub",
    "PrivateKey Path": "private-key-b",
    "Account Address:": "0xbbbede2b4f1d49eff0b156ab0756889a6f2bb68f215399d5015da9ac45921b47"
    }
    }

    Rotate the authentication key of the account linked with the Ledger to the new private key:

    Terminal window
    aptos account rotate-key \
    --assume-yes \
    --new-private-key-file private-key-b \
    --profile ledger-wallet-1000-recovered \
    --save-to-profile temporary-hot-wallet

    Follow the instructions from the CLI prompt:

    Terminal window
    Approve rotation proof challenge signature on your Ledger device
    Terminal window
    Approve transaction on your Ledger device
    Example output
    Terminal window
    {
    "Result": {
    "message": "Saved new profile temporary-hot-wallet",
    "transaction": {
    "transaction_hash": "0xe49782e92d8fd824fd6dce8f6ed42a11cf8ee84c201f3aa639c435e737c80eaa",
    "gas_used": 449,
    "gas_unit_price": 100,
    "sender": "aaac71af5f2a4af4ec2639a15799bf9b945afb061c8bee102b636531c1b00eb5",
    "sequence_number": 1,
    "success": true,
    "timestamp_us": 1717986617911082,
    "version": 631,
    "vm_status": "Executed successfully"
    }
    }

    Since the CLI profile ledger-wallet-1000-recovered is now stale, rename it in case you get interrupted and forget that the private key has been rotated:

    Terminal window
    aptos config rename-profile \
    --profile ledger-wallet-1000-recovered \
    --new-profile-name ledger-wallet-1000-stale
    Example output
    Terminal window
    {
    "Result": "Renamed profile ledger-wallet-1000-recovered to ledger-wallet-1000-stale"
    }
  8. Rotate back to Ledger

    Once you’ve signed the large package publication transaction with the hot key, you can then rotate the authentication key back to the corresponding to the private key on the Ledger at index 1000:

    Terminal window
    aptos account rotate-key \
    --assume-yes \
    --new-derivation-index 1000 \
    --profile temporary-hot-wallet \
    --save-to-profile ledger-wallet-1000

    Follow the instructions from the CLI prompt:

    Terminal window
    Approve rotation proof challenge signature on your Ledger device
    Example output
    Terminal window
    {
    "Result": {
    "message": "Saved new profile ledger-wallet-1000",
    "transaction": {
    "transaction_hash": "0x9503819d4ea13bcd9eafed25984807d86d22e8a9837565a7495b54d13890d103",
    "gas_used": 449,
    "gas_unit_price": 100,
    "sender": "aaac71af5f2a4af4ec2639a15799bf9b945afb061c8bee102b636531c1b00eb5",
    "sequence_number": 2,
    "success": true,
    "timestamp_us": 1717986672963544,
    "version": 742,
    "vm_status": "Executed successfully"
    }
    }
    }

    Verify that the ledger-wallet-1000-stale and ledger-wallet-1000 profiles have the same account address and public_key:

    Terminal window
    aptos config show-profiles --profile ledger-wallet-1000-stale
    aptos config show-profiles --profile ledger-wallet-1000

    Delete the temporary-hot-wallet and ledger-wallet-1000-stale profiles, which you no longer need.

    Terminal window
    aptos config delete-profile --profile temporary-hot-wallet
    aptos config delete-profile --profile ledger-wallet-1000-stale
    Example output
    Terminal window
    {
    "Result": "Deleted profile temporary-hot-wallet"
    }
    {
    "Result": "Deleted profile ledger-wallet-1000-stale"
    }

    Since you no longer need the temporary private key, delete it too.

  9. Clean up

    Delete the remaining test profile:

    Terminal window
    aptos config delete-profile --profile ledger-wallet-1000

    Then stop the localnet.