Documentation Index Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
Use this file to discover all available pages before exploring further.
MEV transaction bundles are atomic collections of transactions submitted to block builders via relays like Flashbots. All transactions in a bundle execute sequentially in the same block, or the entire bundle is discarded.
Overview
Bundle provides type-safe construction and manipulation of MEV bundles for strategies like arbitrage, liquidations, and backrunning. Bundles guarantee atomic execution - either all transactions succeed in order, or none are included.
Type Definition
BundleLike Input
type BundleType = {
// Ordered array of signed transaction bytes
readonly transactions : readonly Uint8Array [];
// Target block number (optional)
readonly blockNumber ?: BlockNumberType ;
// Minimum block timestamp (optional)
readonly minTimestamp ?: Uint256Type ;
// Maximum block timestamp (optional)
readonly maxTimestamp ?: Uint256Type ;
// Transaction hashes allowed to revert (optional)
readonly revertingTxHashes ?: readonly HashType [];
};
type BundleLike = BundleType | {
transactions : ( Uint8Array | string )[];
blockNumber ?: BlockNumberType | bigint | number | string ;
minTimestamp ?: Uint256Type | bigint | number | string ;
maxTimestamp ?: Uint256Type | bigint | number | string ;
revertingTxHashes ?: ( HashType | string )[];
};
Quick Start
Create Bundle
Add Transactions
Submit to Flashbots
import * as Bundle from '@tevm/voltaire/Bundle' ;
// Create from signed transactions
const bundle = Bundle . from ({
transactions: [ signedTx1 , signedTx2 ],
blockNumber: 18500000 n ,
});
// From hex strings
const bundleFromHex = Bundle . from ({
transactions: [
"0x02f8..." , // EIP-1559 tx
"0x02f8..." , // Another tx
],
blockNumber: 18500000 n ,
});
import * as Bundle from '@tevm/voltaire/Bundle' ;
const bundle = Bundle . from ({
transactions: [ victimTx ],
});
// Immutably add transactions
const withBackrun = Bundle . addTransaction ( bundle , backrunTx );
const withSandwich = Bundle . addTransaction ( withBackrun , exitTx );
// Check bundle size
const count = Bundle . size ( withSandwich ); // 3
import * as Bundle from '@tevm/voltaire/Bundle' ;
const bundle = Bundle . from ({
transactions: [ tx1 , tx2 ],
blockNumber: 18500000 n ,
minTimestamp: 1700000000 n ,
maxTimestamp: 1700000012 n ,
});
// Convert to Flashbots RPC format
const params = Bundle . toFlashbotsParams ( bundle );
// Submit via Flashbots RPC
await flashbots . request ({
method: "eth_sendBundle" ,
params: [ params ],
});
API Reference
Constructors
Method Description Bundle.from(value)Create bundle from transactions and options
Methods
Method Description addTransaction(bundle, tx)Add a transaction to the bundle (immutable) size(bundle)Get number of transactions in bundle toHash(bundle, { keccak256 })Compute bundle hash toFlashbotsParams(bundle)Convert to Flashbots RPC format
Bundle Options
Property Type Description transactions(Uint8Array | string)[]Signed transactions in execution order blockNumberbigintTarget block for inclusion minTimestampbigintEarliest valid block timestamp maxTimestampbigintLatest valid block timestamp revertingTxHashesHash[]Tx hashes allowed to revert
Practical Examples
Sandwich Attack Bundle
import * as Bundle from '@tevm/voltaire/Bundle' ;
// Sandwich structure: frontrun -> victim -> backrun
const sandwichBundle = Bundle . from ({
transactions: [
frontrunTx , // Buy before victim
victimTx , // Target transaction
backrunTx , // Sell after victim
],
blockNumber: targetBlock ,
});
const params = Bundle . toFlashbotsParams ( sandwichBundle );
Arbitrage with Revert Protection
import * as Bundle from '@tevm/voltaire/Bundle' ;
import { keccak256 } from '@tevm/voltaire/Keccak256' ;
// Allow first tx to revert (price check might fail)
const arbBundle = Bundle . from ({
transactions: [
priceCheckTx , // May revert if arb opportunity gone
swapTx1 , // DEX A -> DEX B
swapTx2 , // DEX B -> DEX A
],
blockNumber: 18500000 n ,
revertingTxHashes: [
"0x..." + keccak256 ( priceCheckTx ), // Allow this to revert
],
});
Time-Bounded Bundle
import * as Bundle from '@tevm/voltaire/Bundle' ;
// Bundle valid only within 12-second window
const timedBundle = Bundle . from ({
transactions: [ tx1 , tx2 ],
blockNumber: 18500000 n ,
minTimestamp: 1700000000 n ,
maxTimestamp: 1700000012 n , // 12 second window
});
Computing Bundle Hash
import * as Bundle from '@tevm/voltaire/Bundle' ;
import { keccak256 } from '@tevm/voltaire/Keccak256' ;
const bundle = Bundle . from ({
transactions: [ tx1 , tx2 , tx3 ],
});
// Bundle hash is keccak256(concat(tx1Hash, tx2Hash, tx3Hash))
const bundleHash = Bundle . toHash ( bundle , { keccak256 });
console . log ( "Bundle hash:" , bundleHash );
Building Bundle Incrementally
import * as Bundle from '@tevm/voltaire/Bundle' ;
// Start with base transaction
let bundle = Bundle . from ({
transactions: [ baseTx ],
blockNumber: 18500000 n ,
});
// Add transactions based on conditions
if ( needsFrontrun ) {
bundle = Bundle . addTransaction ( bundle , frontrunTx );
}
bundle = Bundle . addTransaction ( bundle , mainTx );
if ( needsBackrun ) {
bundle = Bundle . addTransaction ( bundle , backrunTx );
}
console . log ( `Bundle contains ${ Bundle . size ( bundle ) } transactions` );
Error Handling
Bundle provides typed errors that extend the Voltaire error hierarchy:
import * as Bundle from '@tevm/voltaire/Bundle' ;
import {
InvalidBundleError ,
MissingCryptoDependencyError
} from '@tevm/voltaire/Bundle' ;
try {
// Empty bundle throws
Bundle . from ({ transactions: [] });
} catch ( e ) {
if ( e instanceof InvalidBundleError ) {
console . log ( e . name ); // "InvalidBundleError"
console . log ( e . code ); // "INVALID_BUNDLE"
console . log ( e . message ); // "Bundle must contain at least one transaction"
console . log ( e . value ); // The invalid value
console . log ( e . expected ); // What was expected
}
}
try {
// Invalid transaction format
Bundle . from ({
transactions: [ 123 ], // Not Uint8Array or string
});
} catch ( e ) {
if ( e instanceof InvalidBundleError ) {
console . log ( e . name ); // "InvalidBundleError"
console . log ( e . message ); // "Transaction must be Uint8Array or hex string"
}
}
try {
// Missing crypto dependency
Bundle . toHash ( bundle , {}); // Missing keccak256
} catch ( e ) {
if ( e instanceof MissingCryptoDependencyError ) {
console . log ( e . name ); // "MissingCryptoDependencyError"
console . log ( e . code ); // "MISSING_CRYPTO_DEPENDENCY"
console . log ( e . message ); // "keccak256 not provided"
console . log ( e . expected ); // "{ keccak256: (data: Uint8Array) => Uint8Array }"
}
}
Error Types
Error Extends When Thrown InvalidBundleErrorValidationErrorInvalid bundle format or transaction data MissingCryptoDependencyErrorValidationErrorRequired crypto function not provided
The toFlashbotsParams method converts bundles to the format expected by Flashbots relays:
// Input bundle
const bundle = Bundle . from ({
transactions: [ tx1 , tx2 ],
blockNumber: 18500000 n ,
minTimestamp: 1700000000 n ,
maxTimestamp: 1700000012 n ,
revertingTxHashes: [ hash1 ],
});
// Output format
const params = Bundle . toFlashbotsParams ( bundle );
// {
// txs: ["0x02f8...", "0x02f8..."],
// blockNumber: "0x11a5b20",
// minTimestamp: 1700000000,
// maxTimestamp: 1700000012,
// revertingTxHashes: ["0x..."]
// }
Transaction Transaction encoding and signing
Keccak256 Required for bundle hashing
Hash 32-byte hash type for tx hashes
Flashbots Docs Flashbots Auction documentation