Copy
Ask AI
import { Transaction } from '@tevm/voltaire/Transaction';
import { Secp256k1 } from '@tevm/voltaire/Secp256k1';
import { Address } from '@tevm/voltaire/Address';
import { Hex } from '@tevm/voltaire/Hex';
import { Keccak256 } from '@tevm/voltaire/Keccak256';
// Private key (32 bytes) - NEVER use this in production
const privateKey = Hex.toBytes(
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
);
// Create unsigned EIP-1559 transaction
const unsignedTx = {
type: Transaction.Type.EIP1559,
chainId: 1n, // Ethereum mainnet
nonce: 0n,
maxPriorityFeePerGas: 2_000_000_000n, // 2 gwei tip
maxFeePerGas: 100_000_000_000n, // 100 gwei max
gasLimit: 21000n,
to: Address.from("0x70997970C51812dc3A010C7d01b50e0d17dc79C8"),
value: 1_000_000_000_000_000_000n, // 1 ETH in wei
data: new Uint8Array(),
accessList: [],
};
// Get signing hash (keccak256 of RLP-encoded transaction)
const signingHash = Transaction.EIP1559.getSigningHash(unsignedTx);
// Sign the hash with private key
const signature = Secp256k1.sign(signingHash, privateKey);
// Combine transaction with signature
const signedTx = Transaction.EIP1559.TransactionEIP1559({
...unsignedTx,
yParity: signature.v - 27, // Convert v (27/28) to yParity (0/1)
r: signature.r,
s: signature.s,
});
// Serialize to RLP for broadcasting
const serialized = Transaction.EIP1559.serialize(signedTx);
const signedTxHex = Hex.fromBytes(serialized);
// Verify we can recover the sender
const sender = Transaction.EIP1559.getSender(signedTx);
const senderHex = Address.toChecksummed(sender);
This is a fully executable example. View the complete source with test assertions at
examples/transactions/build-eip1559-transaction.ts.
