On this page
evmSignTransaction
Request a device-confirmed signature for a Legacy or EIP-1559 (Type 2) transaction. The device derives the key from your BIP32 path; your application serializes and broadcasts the result. Decoded transaction details depend on the firmware and calldata.
const result = await HardwareSDK.evmSignTransaction(connectId, deviceId, params);Before you call
- Initialize the SDK and select a device.
- Register UI event handlers and explicitly select the intended wallet.
- Fetch current nonce, gas, and fee values from the target network.
Params
connectIdstringrequiredThe connection identifier returned by device discovery.
deviceIdstringrequiredThe wallet identity returned by getDeviceState.
params.pathstring | number[]requiredBIP32 derivation path with at least three path components.
params.transactionobjectrequiredA Legacy or EIP-1559 transaction. Numeric quantities use hex strings; chainId is a number.
Transaction fields
| Field | Type | Description |
|---|---|---|
chainId | number | Target network chain ID. Lives inside transaction. |
to | string | Destination address; the token contract for ERC-20 calls. |
value | string | Hex-encoded amount in wei. Use 0x0 for ERC-20 calls. |
nonce | string | Transaction count for the sending account, as a hex quantity. |
gasLimit | string | Gas limit, as a hex quantity. |
data | string · optional | Full hex-encoded calldata; use 0x for no calldata. |
maxFeePerGas | string · EIP-1559 | Maximum total fee per gas, as hex-encoded wei. |
maxPriorityFeePerGas | string · EIP-1559 | Maximum priority fee per gas, as hex-encoded wei. |
gasPrice | string · Legacy | Legacy gas price, as hex-encoded wei. |
This page covers EVMTransaction and EVMTransactionEIP1559. See HD paths for path formatting. Make sure your target RPC supports the transaction type.
EIP-1559 requires both fee fields; Legacy uses gasPrice. Do not pass type: 2 to the SDK; select the type when serializing the signed transaction.
Clear Signing
Use this same method for native transfers, ERC-20 transfers, approvals/revocations, and contract calls. For ERC-20 calls, to is the token contract and value is zero; calldata carries the recipient/spender and token amount. Supporting firmware decodes recognized formats automatically. There is no clearSigning, token-metadata, or contract-label parameter.
See the Clear Signing guide for the input/display matrix and unknown-contract behavior. For EIP-712 and Safe owner signatures, use evmSignTypedData.
Examples
The fragments below assume an initialized SDK and selected wallet. Replace the sample recipient and fetch nonce, gas, and fees from the target network before signing.
EIP-1559 requires both maxFeePerGas and maxPriorityFeePerGas. Legacy uses gasPrice.
EIP-1559
const result = await HardwareSDK.evmSignTransaction(connectId, deviceId, {
path: "m/44'/60'/0'/0/0",
useEmptyPassphrase: true,
transaction: {
to: '0xd0d6d6c5fe4a677d343cc433536bb717bae167dd',
value: '0xf4240',
data: '0x',
chainId: 1,
nonce: '0x0',
maxFeePerGas: '0x77359400',
maxPriorityFeePerGas: '0x3b9aca00',
gasLimit: '0x5208',
},
});
if (result.success === false) throw new Error(result.payload.error);These examples select the standard wallet. For a hidden wallet, pass the same wallet common parameters used when confirming the account.
Response
Check success before reading the payload. A successful response contains v, r, and s; the SDK does not broadcast the transaction.
Success
{
success: true,
payload: {
v: string, // hexadecimal string with "0x" prefix
r: string, // hexadecimal string with "0x" prefix
s: string, // hexadecimal string with "0x" prefix
}
}Serialize the signed transaction
The SDK returns a signature; your application assembles and broadcasts the transaction. This example uses ethers v5 packages. Keep the original transaction fields unchanged after the user signs.
import type { UnsignedTransaction } from '@ethersproject/transactions';
import { TransactionTypes, serialize } from '@ethersproject/transactions';
import { splitSignature } from '@ethersproject/bytes';
import { keccak256 } from '@ethersproject/keccak256';
// Illustrative fee values: populate nonce, gas, and fees from your network.
const transaction = {
to: '0x7314e0f1c0e28474bdb6be3e2c3e0453255188f8',
value: '0x0',
data: '0x',
chainId: 1,
nonce: '0x0',
maxFeePerGas: '0x14',
maxPriorityFeePerGas: '0x0',
gasLimit: '0x5208',
};
const result = await HardwareSDK.evmSignTransaction(connectId, deviceId, {
path: "m/44'/60'/0'/0/0",
transaction,
});
if (result.success === false) throw new Error(result.payload.error);
const unsignedTx: UnsignedTransaction = {
...transaction,
nonce: Number.parseInt(transaction.nonce, 16),
type: TransactionTypes.eip1559,
};
const signature = splitSignature({
v: Number(result.payload.v),
r: result.payload.r,
s: result.payload.s,
});
const rawTx = serialize(unsignedTx, signature);
const txid = keccak256(rawTx);
// Submit rawTx using your Ethereum provider after verifying the signed result.For a legacy transaction, use gasPrice instead of the two EIP-1559 fee fields, and serialize it as a legacy transaction.