Skip to Content
📢 Breaking change: Applications using LedgerJS for transport implementation should migrate to the Device Management Kit (DMK). Learn more.
DocumentationLedger Wallet ProviderBlockchainsEVM

EVM with EIP-6963 and EIP-1193

This guide shows how to connect to Ledger Wallet Provider from an EVM dApp and sign messages or transactions through EIP-6963  discovery and the EIP-1193  provider API.

Prerequisites

Ethereum must be enabled for your dAppIdentifier. Select your SDK version:

See Get started - v1 for the full setup guide.

npm install @ledgerhq/ledger-wallet-provider
import { initializeLedgerProvider } from '@ledgerhq/ledger-wallet-provider' import '@ledgerhq/ledger-wallet-provider/styles.css' const cleanup = initializeLedgerProvider({ dAppIdentifier: 'my-dapp', apiKey: 'your-api-key', }) // Call cleanup() when your app unmounts to unregister the EVM provider too.

Supported methods

After connection, use provider.request({ method, params }). Methods handled locally by Ledger include:

MethodPurpose
eth_requestAccountsOpen the Ledger UI and return the selected address
eth_accountsReturn the currently selected account
eth_chainIdReturn the current chain ID (hex)
personal_sign / eth_signSign a message
eth_signTypedData / eth_signTypedData_v4Sign EIP-712 typed data
eth_signTransactionSign a transaction without broadcasting
eth_sendTransactionSign and broadcast a transaction
wallet_switchEthereumChainSwitch to a supported chain ID

Read methods such as eth_call and eth_getBalance are forwarded to the node RPC. See API reference for the full list, events, and error codes.

Discover and connect

Listen for EIP-6963 announcements, then request accounts:

let provider: { request: (args: { method: string; params?: unknown[] }) => Promise<unknown> } | undefined window.addEventListener('eip6963:announceProvider', ((event: CustomEvent) => { const { provider: announced, info } = event.detail if (info.name.toLowerCase().includes('ledger')) { provider = announced } }) as EventListener) window.dispatchEvent(new Event('eip6963:requestProvider')) if (!provider) { throw new Error('Ledger EVM provider not found. Call initializeLedgerProvider first.') } const accounts = await provider.request({ method: 'eth_requestAccounts', params: [], }) as string[] const account = accounts[0]

Sign a message

const signature = await provider.request({ method: 'personal_sign', params: ['Hello from my EVM dApp', account], })

For EIP-712 typed data, use eth_signTypedData_v4 with your typed-data payload. Signing opens the Ledger Wallet Provider UI so the user can confirm on their device.

Sign a transaction

const signedTx = await provider.request({ method: 'eth_signTransaction', params: [ { from: account, to: '0x…', value: '0x0', // gas, data, chainId, … }, ], }) // `signedTx` is the signed raw transaction (you broadcast yourself if needed)

Sign and send a transaction

const txHash = await provider.request({ method: 'eth_sendTransaction', params: [ { from: account, to: '0x…', value: '0x0', }, ], })

Switch chain

await provider.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: '0x1' }], // Ethereum mainnet })

Cleanup

Call the function returned by initializeLedgerProvider when your application unmounts. Cleanup removes the Ledger UI and unregisters any providers that were registered for your partner configuration.

const cleanup = initializeLedgerProvider({ /* options */ }) // Later: cleanup()

Troubleshooting

The eip6963:announceProvider event never fires. Confirm initializeLedgerProvider ran in the browser before dispatching eip6963:requestProvider, that you passed evmBlockchainProviderFactory, and that Ethereum is enabled for your dAppIdentifier. On unsupported platforms (no Web HID / Web Bluetooth), initialization is a no-op and no provider is registered — see Requirements.

request() rejects with error code 4100 (“Unauthorized”). Call eth_requestAccounts first, or the user disconnected. Request accounts again to reopen the Ledger UI.

request() rejects with error code -32603 and message “Ledger Provider is busy”. Blocking requests (connect / sign) are handled one at a time. Wait for the current Ledger UI flow to finish before starting another.

See also

Last updated on
Ledger
Copyright © Ledger SAS. All rights reserved. Ledger, Ledger Stax, Ledger Flex, Ledger Nano, Ledger Nano S, Ledger OS, Ledger Wallet, [LEDGER] (logo), [L] (logo) are trademarks owned by Ledger SAS.