Join the Hardhat team! We are hiring


Hardhat plugin for integration with a Ledger hardware wallet.

# What

This plugin extends the Hardhat provider enabling it to work with a connected Ledger wallet seamlessly.

# Installation

npm install --save-dev @nomicfoundation/hardhat-ledger

And add the following statement to your hardhat.config.js:


Or, if you are using TypeScript, add this to your hardhat.config.ts:

import "@nomicfoundation/hardhat-ledger";

# Tasks

This plugin creates no additional tasks.

# Environment extensions

This plugin adds nothing to the Hardhat Runtime Environment.

# Provider extensions

The provider supplied by Hardhat will be extended using extendProvider, decorating it to be a LedgerProvider. Any successive calls to extendProvider will be added on top of this.

A LedgerProvider knows how to connect and interact with a Ledger wallet

# Usage

The only additional step to make this plugin work is to configure it properly through the Hardhat Config. For example, in your hardhat.config.js:


module.exports = {
  networks: {
    hardhat: {
      ledgerAccounts: [

This will make those three accounts available to the LedgerProvider. If you try to send a transaction or sign something using any of those accounts, the provider will try to connect to the Ledger wallet and find a derivation path for that address. By default, the derivation paths that are tried start from m/44'/60'/0'/0'/0 and go way up to m/44'/60'/20'/0'/0.

An additional (optional) configuration is possible to specify the derivation path that should be used, allowing 'legacy' or otherwise non-standard addresses to still be used with the plugin. An example of such a configuration would be:

hardhat: {
      ledgerAccounts: [...],
      ledgerOptions: {
        derivationFunction: (x) => `m/44'/60'/0'/${x}` // legacy derivation path

If you want to use the provider, you could, for example in a task:

task("sign", "Signs a message", async (_, hre) => {
  const message =
  const account = "0xa809931e3b38059adae9bc5455bc567d0509ab92";

  const signature = await hre.network.provider.request({
    method: "personal_sign",
    params: [

    "Signed message",
    "for Ledger account",
    "and got",

# Errors

The package throws and exports a few errors. In case you ever need to catch and check for them, you can use the public static method present on each of them. For example:

try {
} catch (error) {
  if (DerivationPathError.isDerivationPathError(error)) {
    // error is a DerivationPathError

Same for the other errors, all have their corresponding .isXXXError() method.