GitHub,
Ledger Devs Discord,
Developer Portal
@ledgerhq/hw-app-eth
Ledger Hardware Wallet ETH JavaScript bindings.
Are you adding Ledger support to your software wallet?
You may be using this package to communicate with the Ethereum Nano App.
For a smooth and quick integration:
- See the developers’ documentation on the Developer Portal and
- Go on Discord to chat with developer support and the developer community.
Static Signatures Fallback (for External Library Users)
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.
Installation
If you need static signatures, install the last published version:
npm install @ledgerhq/cryptoassets-evm-signatures@13.5.2
yarn add @ledgerhq/cryptoassets-evm-signatures@13.5.2
Usage
ERC20 Signatures
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,
});
The staticERC20Signatures should be a Record<number, string> where:
- The key is the chain ID (e.g.,
1 for Ethereum mainnet, 137 for Polygon)
- The value is a base64-encoded blob containing the ERC20 signatures for that chain
EIP712 Signatures
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,
});
The EIP712 signatures are objects where:
- Keys are in the format:
${chainId}:${contractAddress}:${schemaHash}
- Values are
MessageFilters objects containing the field filters
Complete Example
import 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", {
cryptoassetsBaseURL: "https://cdn.live.ledger.com/cryptoassets",
calServiceURL: "https://crypto-assets-service.api.ledger.com",
staticERC20Signatures: erc20Signatures,
staticEIP712SignaturesV1: EIP712CAL,
staticEIP712SignaturesV2: EIP712CALV2,
});
How It Works
Notes
- Static signatures are not included by default to reduce bundle size
- Static signatures may become outdated over time
- The dynamic CAL service is always preferred when available
- Static signatures are only used as a fallback when the dynamic service is unavailable or fails
API
Table of Contents
Eth
Ethereum API
Parameters
transport Transport
scrambleKey (optional, default "w0w")
loadConfig LoadConfig (optional, default {})
Examples
import Eth from "@ledgerhq/hw-app-eth";
const eth = new Eth(transport)
getAddress
get Ethereum address for a given BIP 32 path.
Parameters
Examples
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
signTransaction
You can sign a transaction and retrieve v, r, s given the raw transaction and the BIP 32 path of the account to sign.
Parameters
path string : the BIP32 path to sign the transaction on
rawTxHex string : the raw ethereum transaction in hexadecimal to sign
resolution (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.
Examples
import { ledgerService } from "@ledgerhq/hw-app-eth"
const tx = "e8018504e3b292008252089428ee52a8f3d6e5d15f8b131996950d7f296c7952872bd72a2487400080";
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}>
clearSignTransaction
Helper to get resolution and signature of a transaction in a single method
Parameters
path string : the BIP32 path to sign the transaction on
rawTxHex string : the raw ethereum transaction in hexadecimal to sign
resolutionConfig ResolutionConfig : configuration about what should be clear signed in the transaction
throwOnError : optional parameter to determine if a failing resolution of the transaction should throw an error or not (optional, default false)
Examples
const tx = "e8018504e3b292008252089428ee52a8f3d6e5d15f8b131996950d7f296c7952872bd72a2487400080";
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}>
getAppConfiguration
Returns Promise<{arbitraryDataEnabled: number, erc20ProvisioningNecessary: number, starkEnabled: number, starkv2Supported: number, version: string}>
signPersonalMessage
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.
Parameters
Examples
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}>
signEIP712HashedMessage
Sign a prepared message following web3.eth.signTypedData specification. The host computes the domain separator and hashStruct(message)
Parameters
Examples
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}>
signEIP712Message
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 ⚠️
Parameters
path String derivationPath
jsonMessage Object message to sign
fullImplem Boolean use the legacy implementation (optional, default false)
Examples
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
getChallenge
Method returning a 4 bytes TLV challenge as an hexa string
Returns Promise<string>
starkGetPublicKey
get Stark public key for a given BIP 32 path.
Parameters
Returns Promise<Buffer> the Stark public key
starkSignOrder
sign a Stark order
Parameters
path string a path in BIP 32 format
sourceTokenAddress (string | undefined)
sourceQuantization BigNumber quantization used for the source token
destinationTokenAddress (string | undefined)
destinationQuantization BigNumber quantization used for the destination token
sourceVault number ID of the source vault
destinationVault number ID of the destination vault
amountSell BigNumber amount to sell
amountBuy BigNumber amount to buy
nonce number transaction nonce
timestamp number transaction validity timestamp
Returns Promise<(Buffer | {r: string, s: string})> the signature
starkSignOrder_v2
sign a Stark order using the Starkex V2 protocol
Parameters
path string a path in BIP 32 format
sourceTokenAddress (string | undefined)
sourceQuantizationType StarkQuantizationType quantization type used for the source token
sourceQuantization (BigNumber | undefined)
sourceMintableBlobOrTokenId (BigNumber | undefined)
destinationTokenAddress (string | undefined)
destinationQuantizationType StarkQuantizationType quantization type used for the destination token
destinationQuantization (BigNumber | undefined)
destinationMintableBlobOrTokenId (BigNumber | undefined)
sourceVault number ID of the source vault
destinationVault number ID of the destination vault
amountSell BigNumber amount to sell
amountBuy BigNumber amount to buy
nonce number transaction nonce
timestamp number transaction validity timestamp
Returns Promise<(Buffer | {r: string, s: string})> the signature
starkSignTransfer
sign a Stark transfer
Parameters
path string a path in BIP 32 format
transferTokenAddress (string | undefined)
transferQuantization BigNumber quantization used for the token to be transferred
targetPublicKey string target Stark public key
sourceVault number ID of the source vault
destinationVault number ID of the destination vault
amountTransfer BigNumber amount to transfer
nonce number transaction nonce
timestamp number transaction validity timestamp
Returns Promise<(Buffer | {r: string, s: string})> the signature
starkSignTransfer_v2
sign a Stark transfer or conditional transfer using the Starkex V2 protocol
Parameters
path string a path in BIP 32 format
transferTokenAddress (string | undefined)
transferQuantizationType StarkQuantizationType quantization type used for the token to be transferred
transferQuantization (BigNumber | undefined)
transferMintableBlobOrTokenId (BigNumber | undefined)
targetPublicKey string target Stark public key
sourceVault number ID of the source vault
destinationVault number ID of the destination vault
amountTransfer BigNumber amount to transfer
nonce number transaction nonce
timestamp number transaction validity timestamp
conditionalTransferAddress string?
conditionalTransferFact BigNumber?
Returns Promise<(Buffer | {r: string, s: string})> the signature
starkProvideQuantum
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
Parameters
operationContract (string | undefined) contract address of the token to be transferred (not present for ETH)
operationQuantization BigNumber quantization used for the token to be transferred
Returns Promise<boolean>
starkProvideQuantum_v2
provide 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
Parameters
operationContract (string | undefined) contract address of the token to be transferred (not present for ETH)
operationQuantizationType StarkQuantizationType quantization type of the token to be transferred
operationQuantization BigNumber?
operationMintableBlobOrTokenId BigNumber?
Returns Promise<boolean>
starkUnsafeSign
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.
Parameters
path string a path in BIP 32 format
hash string hexadecimal hash to sign
Returns Promise<(Buffer | {r: string, s: string})> the signature
eth2GetPublicKey
get an Ethereum 2 BLS-12 381 public key for a given BIP 32 path.
Parameters
Examples
eth.eth2GetPublicKey("12381/3600/0/0").then(o => o.publicKey)
Returns Promise<{publicKey: string}> an object with a publicKey
eth2SetWithdrawalIndex
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
Parameters
withdrawalIndex number index path in the EIP 2334 path m/12381/3600/withdrawalIndex/0
Returns Promise<boolean> True if the method was executed successfully
getEIP1024PublicEncryptionKey
get a public encryption key on Curve25519 according to EIP 1024
Parameters
Examples
eth.getEIP1024PublicEncryptionKey("44'/60'/0'/0/0").then(o => o.publicKey)
Returns Promise<{publicKey: string}> an object with a publicKey
getEIP1024SharedSecret
get a shared secret on Curve25519 according to EIP 1024
Parameters
path string a path in BIP 32 format
remotePublicKeyHex string remote Curve25519 public key
boolDisplay boolean?
Examples
eth.getEIP1024SharedSecret("44'/60'/0'/0/0", "87020e80af6e07a6e4697f091eacadb9e7e6629cb7e5a8a371689a3ed53b3d64").then(o => o.sharedSecret)
Returns Promise<{sharedSecret: string}> an object with a shared secret
provideERC20TokenInformation
provides a trusted description of an ERC 20 token to associate a contract address with a ticker and number of decimals.
Parameters
data string stringified buffer of ERC20 signature
Returns Promise<boolean> a boolean
setExternalPlugin
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.
Parameters
Returns Promise<boolean> a boolean
setPlugin
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.
Parameters
data string stringified buffer of plugin signature
Returns Promise<boolean> a boolean
provideNFTInformation
provides a trusted description of an NFT to associate a contract address with a collectionName.
Parameters
data string stringified buffer of the NFT description
Returns Promise<boolean> a boolean
provideDomainName
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.
Parameters
data string an stringied buffer of some TLV encoded data to represent the domain
Returns Promise<boolean> a boolean
loadInfosForContractMethod
Retrieve the metadatas a given contract address and a method selector
Parameters
Returns Promise<(ContractMethod | undefined)>
byContractAddressAndChainId
Retrieve the token information by a given contract address if any
Parameters
contract string
chainId number
erc20SignaturesBlob (string | null)?
userLoadConfig LoadConfig?
Returns ReturnType<any>
ResolutionConfig
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?}
Properties