>
>
Join the Hardhat team! We are hiring
>
>
npm
hardhat

#hardhat-ledger

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:

require("@nomicfoundation/hardhat-ledger");

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:

require("@nomicfoundation/hardhat-ledger");

module.exports = {
  networks: {
    hardhat: {
      ledgerAccounts: [
        "0xa809931e3b38059adae9bc5455bc567d0509ab92",
        "0xda6a52afdae5ff66aa786da68754a227331f56e3",
        "0xbc307688a80ec5ed0edc1279c44c1b34f7746bda",
      ],
    },
  },
};

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 =
    "0x5417aa2a18a44da0675524453ff108c545382f0d7e26605c56bba47c21b5e979";
  const account = "0xa809931e3b38059adae9bc5455bc567d0509ab92";

  const signature = await hre.network.provider.request({
    method: "personal_sign",
    params: [
      "0x5417aa2a18a44da0675524453ff108c545382f0d7e26605c56bba47c21b5e979",
      account,
    ],
  });

  console.log(
    "Signed message",
    message,
    "for Ledger account",
    account,
    "and got",
    signature
  );
});

# 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.