Skip to Content
Hardware
HARDWARE SDK / ETHEREUM & EVM

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);
01 Prepare02 Confirm on device03 Serialize & send

Before you call

Params

connectIdstringrequired

The connection identifier returned by device discovery.

deviceIdstringrequired

The wallet identity returned by getDeviceState.

params.pathstring | number[]required

BIP32 derivation path with at least three path components.

params.transactionobjectrequired

A Legacy or EIP-1559 transaction. Numeric quantities use hex strings; chainId is a number.

Optional common params

Transaction fields

FieldTypeDescription
chainIdnumberTarget network chain ID. Lives inside transaction.
tostringDestination address; the token contract for ERC-20 calls.
valuestringHex-encoded amount in wei. Use 0x0 for ERC-20 calls.
noncestringTransaction count for the sending account, as a hex quantity.
gasLimitstringGas limit, as a hex quantity.
datastring · optionalFull hex-encoded calldata; use 0x for no calldata.
maxFeePerGasstring · EIP-1559Maximum total fee per gas, as hex-encoded wei.
maxPriorityFeePerGasstring · EIP-1559Maximum priority fee per gas, as hex-encoded wei.
gasPricestring · LegacyLegacy 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.

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: 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.

Last updated on