Use the Ethereum Signer
This module provides the implementation of the Ledger Ethereum Signer for the Mobile Device Management Kit. It enables interaction with the Ethereum application on a Ledger device:
- Retrieving the Ethereum address using a given derivation path
- Signing an Ethereum transaction (Clear Signing )
- Signing a message displayed on a Ledger device
- Signing an EIP-712 typed data message
🔹 Index
🔹 How it works
The Ledger Ethereum Signer uses the interface provided by the Device Management Kit to establish communication with the Ledger device and execute operations. Communication is performed using APDUs , encapsulated within Command objects, which are in turn encapsulated within DeviceAction objects to handle real-world scenarios.
For transaction signing, the Signer integrates with the Context Module to provide context data to the device, enabling Clear Signing — the display of human-readable transaction details on the device screen.
🔹 Initialisation
To initialize an Ethereum signer instance, you need a DeviceManagementKitApi instance. Use the ethereumSigner builder DSL:
import com.ledger.signer.eth.ethereumSigner
val signerEth = ethereumSigner(
deviceManagementKit = dmk,
originToken = "your-origin-token",
) {
context = applicationContext // required on Android
}The originToken is required by the default Context Module for transaction
checks. It should be delivered by Ledger — without it, Transaction Checks will
not be available.
You can also customize the Context Module endpoints:
val signerEth = ethereumSigner(
deviceManagementKit = dmk,
originToken = "your-origin-token",
) {
context = applicationContext
calUrl = "https://your-custom-cal-url"
metadataServiceUrl = "https://your-custom-metadata-url"
transactionCheckUrl = "https://your-custom-tx-check-url"
enableLog = true
}🔹 Use Cases
The EthereumSigner exposes 4 dedicated methods. Each returns a Flow<DeviceActionResult<T>> — a stream of state updates tracking the operation’s progress.
Use Case 1: Get Address
Retrieve the Ethereum address for a given derivation path.
val flow: Flow<DeviceActionResult<EthereumAddress>> = signerEth.getAddress(
deviceUid = connectedDevice.uid,
request = GetEthereumAddressRequest(
derivationPath = "44'/60'/0'/0/0",
checkOnDevice = false,
withChainCode = false,
),
)Parameters
-
deviceUid- Required
- Type:
String - The UID of the connected device, from
ConnectedDevice.uid.
-
request- Required
- Type:
GetEthereumAddressRequest
Field Type Description derivationPathStringDerivation path, e.g. "44'/60'/0'/0/0"checkOnDeviceBooleanWhether user confirmation is required on the device withChainCodeBooleanWhether to return the chain code
Returns
Flow<DeviceActionResult<EthereumAddress>>
data class EthereumAddress(
val publicKey: String, // Public key derived from the given path
val address: String, // Ethereum address (hex format)
val chainCode: String?, // Chain code (if requested)
)Use Case 2: Sign Transaction
Sign an Ethereum transaction using Clear Signing on the Ledger device. The Context Module automatically enriches the transaction with token, NFT, and trusted name information so the device can display human-readable details.
val flow: Flow<DeviceActionResult<Signature>> = signerEth.signTransaction(
deviceUid = connectedDevice.uid,
request = SignEthereumRequest(
derivationPath = "44'/60'/0'/0/0",
value = rawTransactionHex,
),
)A transaction that already carries a signature is accepted: the signature is dropped and the transaction is signed again.
Parameters
-
deviceUid- Required
- Type:
String - The UID of the connected device.
-
request- Required
- Type:
SignEthereumRequest
Field Type Description derivationPathStringDerivation path, e.g. "44'/60'/0'/0/0"valueStringRLP-encoded transaction as hex string isHexadecimalValueBooleanIgnored for transaction signing (default false)
Returns
Flow<DeviceActionResult<Signature>>
data class Signature(
val r: String, // R component of the ECDSA signature (hex)
val s: String, // S component of the ECDSA signature (hex)
val v: Int, // Recovery parameter
)Use Case 3: Sign Personal Message
Sign a text message (EIP-191 personal_sign) displayed on the Ledger device.
val flow: Flow<DeviceActionResult<Signature>> = signerEth.signPersonalMessage(
deviceUid = connectedDevice.uid,
request = SignEthereumRequest(
derivationPath = "44'/60'/0'/0/0",
value = "Hello from Ledger",
isHexadecimalValue = false,
),
)Parameters
-
deviceUid- Required
- Type:
String - The UID of the connected device.
-
request- Required
- Type:
SignEthereumRequest
Field Type Description derivationPathStringDerivation path, e.g. "44'/60'/0'/0/0"valueStringMessage to sign (UTF-8 string or hex) isHexadecimalValueBooleanSet to trueifvalueis hexadecimal
Returns
Flow<DeviceActionResult<Signature>>
data class Signature(
val r: String, // R component of the ECDSA signature (hex)
val s: String, // S component of the ECDSA signature (hex)
val v: Int, // Recovery parameter
)Use Case 4: Sign Typed Data
Sign an EIP-712 typed data message. The Context Module provides the data needed to display the fields in a readable way on the device.
val flow: Flow<DeviceActionResult<Signature>> = signerEth.signEip712Message(
deviceUid = connectedDevice.uid,
request = SignEthereumRequest(
derivationPath = "44'/60'/0'/0/0",
value = typedDataJson,
),
)Parameters
-
deviceUid- Required
- Type:
String - The UID of the connected device.
-
request- Required
- Type:
SignEthereumRequest
Field Type Description derivationPathStringDerivation path, e.g. "44'/60'/0'/0/0"valueStringEIP-712 typed data (domain, types, message) as a JSON string
Returns
Flow<DeviceActionResult<Signature>>
data class Signature(
val r: String, // R component of the ECDSA signature (hex)
val s: String, // S component of the ECDSA signature (hex)
val v: Int, // Recovery parameter
)🔹 Errors
When the user rejects an operation on the device, the failure reason is EthereumErrors.CancelByUser. The other Ethereum application errors are listed in EthereumErrors.
🔹 Lifecycle
The EthereumSigner is initialized once per process and must be initialized before use. Building a second instance throws EthereumSigner already initialized, and there is no public destroy or reset API: treat the signer as a process-wide singleton.