
Security News
Critical Security Vulnerability in React Server Components
React disclosed a CVSS 10.0 RCE in React Server Components and is advising users to upgrade affected packages and frameworks to patched versions now.
@ledgerhq/hw-app-eth
Advanced tools
GitHub, Ledger Devs Discord, Developer Portal
Ledger Hardware Wallet ETH JavaScript bindings.
You may be using this package to communicate with the Ethereum Nano App.
For a smooth and quick integration:
The library now relies on dynamic CAL (Crypto Assets List) services for ERC20 and EIP712 signatures. However, if you need offline support or want to use static signatures as a fallback, you can inject them from the deprecated @ledgerhq/cryptoassets-evm-signatures package.
If you need static signatures, install the last published version:
npm install @ledgerhq/cryptoassets-evm-signatures@13.5.2
# or
yarn add @ledgerhq/cryptoassets-evm-signatures@13.5.2
To inject static ERC20 signatures:
import Eth from "@ledgerhq/hw-app-eth";
import { signatures as erc20Signatures } from "@ledgerhq/cryptoassets-evm-signatures/data/evm/index";
const eth = new Eth(transport, "w0w", {
staticERC20Signatures: erc20Signatures,
// ... other config options
});
The staticERC20Signatures should be a Record<number, string> where:
1 for Ethereum mainnet, 137 for Polygon)To inject static EIP712 signatures:
import Eth from "@ledgerhq/hw-app-eth";
import EIP712CAL from "@ledgerhq/cryptoassets-evm-signatures/data/eip712";
import EIP712CALV2 from "@ledgerhq/cryptoassets-evm-signatures/data/eip712_v2";
const eth = new Eth(transport, "w0w", {
staticEIP712SignaturesV1: EIP712CAL,
staticEIP712SignaturesV2: EIP712CALV2,
// ... other config options
});
The EIP712 signatures are objects where:
${chainId}:${contractAddress}:${schemaHash}MessageFilters objects containing the field filtersimport Eth from "@ledgerhq/hw-app-eth";
import { signatures as erc20Signatures } from "@ledgerhq/cryptoassets-evm-signatures/data/evm/index";
import EIP712CAL from "@ledgerhq/cryptoassets-evm-signatures/data/eip712";
import EIP712CALV2 from "@ledgerhq/cryptoassets-evm-signatures/data/eip712_v2";
const eth = new Eth(transport, "w0w", {
// Dynamic CAL service (preferred)
cryptoassetsBaseURL: "https://cdn.live.ledger.com/cryptoassets",
calServiceURL: "https://crypto-assets-service.api.ledger.com",
// Static fallbacks (optional, for offline support)
staticERC20Signatures: erc20Signatures,
staticEIP712SignaturesV1: EIP712CAL,
staticEIP712SignaturesV2: EIP712CALV2,
});
ERC20 Signatures: When resolving ERC20 token information:
staticERC20Signatures[chainId]null if neither is availableEIP712 Signatures: When resolving EIP712 message filters:
calServiceURL is providedstaticEIP712SignaturesV1 if the device requires v1 filtersstaticEIP712SignaturesV2 otherwiseundefined if neither is availableEthereum API
transport Transport scrambleKey (optional, default "w0w")loadConfig LoadConfig (optional, default {})import Eth from "@ledgerhq/hw-app-eth";
const eth = new Eth(transport)
get Ethereum address for a given BIP 32 path.
eth.getAddress("44'/60'/0'/0/0").then(o => o.address)
Returns Promise<{publicKey: string, address: string, chainCode: string?}> an object with a publicKey, address and (optionally) chainCode
You can sign a transaction and retrieve v, r, s given the raw transaction and the BIP 32 path of the account to sign.
path string : the BIP32 path to sign the transaction onrawTxHex string : the raw ethereum transaction in hexadecimal to signresolution (LedgerEthTransactionResolution | null)? : resolution is an object with all "resolved" metadata necessary to allow the device to clear sign information. This includes: ERC20 token information, plugins, contracts, NFT signatures,... You must explicitly provide something to avoid having a warning. By default, you can use Ledger's service or your own resolution service. See services/types.js for the contract. Setting the value to "null" will fallback everything to blind signing but will still allow the device to sign the transaction.import { ledgerService } from "@ledgerhq/hw-app-eth"
const tx = "e8018504e3b292008252089428ee52a8f3d6e5d15f8b131996950d7f296c7952872bd72a2487400080"; // raw tx to sign
const resolution = await ledgerService.resolveTransaction(tx);
const result = eth.signTransaction("44'/60'/0'/0/0", tx, resolution);
console.log(result);
Returns Promise<{s: string, v: string, r: string}>
Helper to get resolution and signature of a transaction in a single method
path string : the BIP32 path to sign the transaction onrawTxHex string : the raw ethereum transaction in hexadecimal to signresolutionConfig ResolutionConfig : configuration about what should be clear signed in the transactionthrowOnError : optional parameter to determine if a failing resolution of the transaction should throw an error or not (optional, default false)const tx = "e8018504e3b292008252089428ee52a8f3d6e5d15f8b131996950d7f296c7952872bd72a2487400080"; // raw tx to sign
const result = eth.clearSignTransaction("44'/60'/0'/0/0", tx, { erc20: true, externalPlugins: true, nft: true});
console.log(result);
Returns Promise<{r: string, s: string, v: string}>
Returns Promise<{arbitraryDataEnabled: number, erc20ProvisioningNecessary: number, starkEnabled: number, starkv2Supported: number, version: string}>
You can sign a message according to eth_sign RPC call and retrieve v, r, s given the message and the BIP 32 path of the account to sign.
eth.signPersonalMessage("44'/60'/0'/0/0", Buffer.from("test").toString("hex")).then(result => {
var v = result['v'] - 27;
v = v.toString(16);
if (v.length < 2) {
v = "0" + v;
}
console.log("Signature 0x" + result['r'] + result['s'] + v);
})
Returns Promise<{v: number, s: string, r: string}>
Sign a prepared message following web3.eth.signTypedData specification. The host computes the domain separator and hashStruct(message)
eth.signEIP712HashedMessage("44'/60'/0'/0/0", Buffer.from("0101010101010101010101010101010101010101010101010101010101010101").toString("hex"), Buffer.from("0202020202020202020202020202020202020202020202020202020202020202").toString("hex")).then(result => {
var v = result['v'] - 27;
v = v.toString(16);
if (v.length < 2) {
v = "0" + v;
}
console.log("Signature 0x" + result['r'] + result['s'] + v);
})
Returns Promise<{v: number, s: string, r: string}>
Sign an EIP-721 formatted message following the specification here: https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/ethapp.asc#sign-eth-eip-712 ⚠️ This method is not compatible with nano S (LNS). Make sure to use a try/catch to fallback on the signEIP712HashedMessage method ⚠️
path String derivationPathjsonMessage Object message to signfullImplem Boolean use the legacy implementation (optional, default false)eth.signEIP721Message("44'/60'/0'/0/0", {
domain: {
chainId: 69,
name: "Da Domain",
verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
version: "1"
},
types: {
"EIP712Domain": [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
],
"Test": [
{ name: "contents", type: "string" }
]
},
primaryType: "Test",
message: {contents: "Hello, Bob!"},
})
Returns Promise
Method returning a 4 bytes TLV challenge as an hexa string
get Stark public key for a given BIP 32 path.
Returns Promise<Buffer> the Stark public key
sign a Stark order
path string a path in BIP 32 formatsourceTokenAddress (string | undefined) sourceQuantization BigNumber quantization used for the source tokendestinationTokenAddress (string | undefined) destinationQuantization BigNumber quantization used for the destination tokensourceVault number ID of the source vaultdestinationVault number ID of the destination vaultamountSell BigNumber amount to sellamountBuy BigNumber amount to buynonce number transaction noncetimestamp number transaction validity timestampReturns Promise<(Buffer | {r: string, s: string})> the signature
sign a Stark order using the Starkex V2 protocol
path string a path in BIP 32 formatsourceTokenAddress (string | undefined) sourceQuantizationType StarkQuantizationType quantization type used for the source tokensourceQuantization (BigNumber | undefined) sourceMintableBlobOrTokenId (BigNumber | undefined) destinationTokenAddress (string | undefined) destinationQuantizationType StarkQuantizationType quantization type used for the destination tokendestinationQuantization (BigNumber | undefined) destinationMintableBlobOrTokenId (BigNumber | undefined) sourceVault number ID of the source vaultdestinationVault number ID of the destination vaultamountSell BigNumber amount to sellamountBuy BigNumber amount to buynonce number transaction noncetimestamp number transaction validity timestampReturns Promise<(Buffer | {r: string, s: string})> the signature
sign a Stark transfer
path string a path in BIP 32 formattransferTokenAddress (string | undefined) transferQuantization BigNumber quantization used for the token to be transferredtargetPublicKey string target Stark public keysourceVault number ID of the source vaultdestinationVault number ID of the destination vaultamountTransfer BigNumber amount to transfernonce number transaction noncetimestamp number transaction validity timestampReturns Promise<(Buffer | {r: string, s: string})> the signature
sign a Stark transfer or conditional transfer using the Starkex V2 protocol
path string a path in BIP 32 formattransferTokenAddress (string | undefined) transferQuantizationType StarkQuantizationType quantization type used for the token to be transferredtransferQuantization (BigNumber | undefined) transferMintableBlobOrTokenId (BigNumber | undefined) targetPublicKey string target Stark public keysourceVault number ID of the source vaultdestinationVault number ID of the destination vaultamountTransfer BigNumber amount to transfernonce number transaction noncetimestamp number transaction validity timestampconditionalTransferAddress string? conditionalTransferFact BigNumber? Returns Promise<(Buffer | {r: string, s: string})> the signature
provide quantization information before singing a deposit or withdrawal Stark powered contract call
It shall be run following a provideERC20TokenInformation call for the given contract
operationContract (string | undefined) contract address of the token to be transferred (not present for ETH)operationQuantization BigNumber quantization used for the token to be transferredprovide quantization information before singing a deposit or withdrawal Stark powered contract call using the Starkex V2 protocol
It shall be run following a provideERC20TokenInformation call for the given contract
operationContract (string | undefined) contract address of the token to be transferred (not present for ETH)operationQuantizationType StarkQuantizationType quantization type of the token to be transferredoperationQuantization BigNumber? operationMintableBlobOrTokenId BigNumber? sign the given hash over the Stark curve It is intended for speed of execution in case an unknown Stark model is pushed and should be avoided as much as possible.
Returns Promise<(Buffer | {r: string, s: string})> the signature
get an Ethereum 2 BLS-12 381 public key for a given BIP 32 path.
eth.eth2GetPublicKey("12381/3600/0/0").then(o => o.publicKey)
Returns Promise<{publicKey: string}> an object with a publicKey
Set the index of a Withdrawal key used as withdrawal credentials in an ETH 2 deposit contract call signature
It shall be run before the ETH 2 deposit transaction is signed. If not called, the index is set to 0
withdrawalIndex number index path in the EIP 2334 path m/12381/3600/withdrawalIndex/0Returns Promise<boolean> True if the method was executed successfully
get a public encryption key on Curve25519 according to EIP 1024
eth.getEIP1024PublicEncryptionKey("44'/60'/0'/0/0").then(o => o.publicKey)
Returns Promise<{publicKey: string}> an object with a publicKey
get a shared secret on Curve25519 according to EIP 1024
path string a path in BIP 32 formatremotePublicKeyHex string remote Curve25519 public keyboolDisplay boolean? eth.getEIP1024SharedSecret("44'/60'/0'/0/0", "87020e80af6e07a6e4697f091eacadb9e7e6629cb7e5a8a371689a3ed53b3d64").then(o => o.sharedSecret)
Returns Promise<{sharedSecret: string}> an object with a shared secret
provides a trusted description of an ERC 20 token to associate a contract address with a ticker and number of decimals.
data string stringified buffer of ERC20 signatureReturns Promise<boolean> a boolean
provides the name of a trusted binding of a plugin with a contract address and a supported method selector. This plugin will be called to interpret contract data in the following transaction signing command.
Returns Promise<boolean> a boolean
provides the name of a trusted binding of a plugin with a contract address and a supported method selector. This plugin will be called to interpret contract data in the following transaction signing command.
data string stringified buffer of plugin signatureReturns Promise<boolean> a boolean
provides a trusted description of an NFT to associate a contract address with a collectionName.
data string stringified buffer of the NFT descriptionReturns Promise<boolean> a boolean
provides a domain name (like ENS) to be displayed during transactions in place of the address it is associated to. It shall be run just before a transaction involving the associated address that would be displayed on the device.
data string an stringied buffer of some TLV encoded data to represent the domainReturns Promise<boolean> a boolean
Retrieve the metadatas a given contract address and a method selector
Returns Promise<(ContractMethod | undefined)>
Retrieve the token information by a given contract address if any
Returns ReturnType<any>
Allows to configure precisely what the service need to resolve. for instance you can set nft:true if you need clear signing on NFTs. If you set it and it is not a NFT transaction, it should still work but will do a useless service resolution.
Type: {nft: boolean?, externalPlugins: boolean?, erc20: boolean?, domains: Array<DomainDescriptor>?, uniswapV3: boolean?}
FAQs
Ledger Hardware Wallet Ethereum Application API
The npm package @ledgerhq/hw-app-eth receives a total of 141,863 weekly downloads. As such, @ledgerhq/hw-app-eth popularity was classified as popular.
We found that @ledgerhq/hw-app-eth demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 7 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
React disclosed a CVSS 10.0 RCE in React Server Components and is advising users to upgrade affected packages and frameworks to patched versions now.

Research
/Security News
We spotted a wave of auto-generated “elf-*” npm packages published every two minutes from new accounts, with simple malware variants and early takedowns underway.

Research
/Security News
Malicious Rust crate evm-units disguised as an EVM version helper downloads and silently executes OS-specific payloads likely aimed at crypto theft.