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

# Bundle

> MEV transaction bundles for atomic execution via Flashbots and block builders

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.

<Tabs>
  <Tab title="Type Definition">
    ```typescript theme={null}
    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[];
    };
    ```
  </Tab>

  <Tab title="BundleLike Input">
    ```typescript theme={null}
    type BundleLike = BundleType | {
      transactions: (Uint8Array | string)[];
      blockNumber?: BlockNumberType | bigint | number | string;
      minTimestamp?: Uint256Type | bigint | number | string;
      maxTimestamp?: Uint256Type | bigint | number | string;
      revertingTxHashes?: (HashType | string)[];
    };
    ```
  </Tab>
</Tabs>

## Quick Start

<Tabs>
  <Tab title="Create Bundle">
    ```typescript theme={null}
    import * as Bundle from '@tevm/voltaire/Bundle';

    // Create from signed transactions
    const bundle = Bundle.from({
      transactions: [signedTx1, signedTx2],
      blockNumber: 18500000n,
    });

    // From hex strings
    const bundleFromHex = Bundle.from({
      transactions: [
        "0x02f8...", // EIP-1559 tx
        "0x02f8...", // Another tx
      ],
      blockNumber: 18500000n,
    });
    ```
  </Tab>

  <Tab title="Add Transactions">
    ```typescript theme={null}
    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
    ```
  </Tab>

  <Tab title="Submit to Flashbots">
    ```typescript theme={null}
    import * as Bundle from '@tevm/voltaire/Bundle';

    const bundle = Bundle.from({
      transactions: [tx1, tx2],
      blockNumber: 18500000n,
      minTimestamp: 1700000000n,
      maxTimestamp: 1700000012n,
    });

    // Convert to Flashbots RPC format
    const params = Bundle.toFlashbotsParams(bundle);

    // Submit via Flashbots RPC
    await flashbots.request({
      method: "eth_sendBundle",
      params: [params],
    });
    ```
  </Tab>
</Tabs>

## 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 |
| `blockNumber`       | `bigint`                   | Target block for inclusion             |
| `minTimestamp`      | `bigint`                   | Earliest valid block timestamp         |
| `maxTimestamp`      | `bigint`                   | Latest valid block timestamp           |
| `revertingTxHashes` | `Hash[]`                   | Tx hashes allowed to revert            |

## Practical Examples

### Sandwich Attack Bundle

```typescript theme={null}
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

```typescript theme={null}
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: 18500000n,
  revertingTxHashes: [
    "0x..." + keccak256(priceCheckTx), // Allow this to revert
  ],
});
```

### Time-Bounded Bundle

```typescript theme={null}
import * as Bundle from '@tevm/voltaire/Bundle';

// Bundle valid only within 12-second window
const timedBundle = Bundle.from({
  transactions: [tx1, tx2],
  blockNumber: 18500000n,
  minTimestamp: 1700000000n,
  maxTimestamp: 1700000012n, // 12 second window
});
```

### Computing Bundle Hash

```typescript theme={null}
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

```typescript theme={null}
import * as Bundle from '@tevm/voltaire/Bundle';

// Start with base transaction
let bundle = Bundle.from({
  transactions: [baseTx],
  blockNumber: 18500000n,
});

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

```typescript theme={null}
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                               |
| ------------------------------ | ----------------- | ----------------------------------------- |
| `InvalidBundleError`           | `ValidationError` | Invalid bundle format or transaction data |
| `MissingCryptoDependencyError` | `ValidationError` | Required crypto function not provided     |

## Flashbots RPC Format

The `toFlashbotsParams` method converts bundles to the format expected by Flashbots relays:

```typescript theme={null}
// Input bundle
const bundle = Bundle.from({
  transactions: [tx1, tx2],
  blockNumber: 18500000n,
  minTimestamp: 1700000000n,
  maxTimestamp: 1700000012n,
  revertingTxHashes: [hash1],
});

// Output format
const params = Bundle.toFlashbotsParams(bundle);
// {
//   txs: ["0x02f8...", "0x02f8..."],
//   blockNumber: "0x11a5b20",
//   minTimestamp: 1700000000,
//   maxTimestamp: 1700000012,
//   revertingTxHashes: ["0x..."]
// }
```

## Related

<CardGroup cols={2}>
  <Card title="Transaction" icon="arrow-right-arrow-left" href="/primitives/transaction">
    Transaction encoding and signing
  </Card>

  <Card title="Keccak256" icon="hashtag" href="/crypto/keccak256">
    Required for bundle hashing
  </Card>

  <Card title="Hash" icon="fingerprint" href="/primitives/hash">
    32-byte hash type for tx hashes
  </Card>

  <Card title="Flashbots Docs" icon="book" href="https://docs.flashbots.net/flashbots-auction/overview">
    Flashbots Auction documentation
  </Card>
</CardGroup>
