# Batch Calls

:::info
This guide is intended to be low-level. If you are looking for a high-level abstraction, check out
[Viem's Batch Calls guide](https://viem.sh/tempo/guides/batch-calls).
:::

## Overview

Tempo transaction envelopes contain a `calls` array instead of a single `to`, `value`, and
`data` tuple. The calls execute in order as one atomic transaction. If one call reverts, the
transaction does not keep changes from earlier calls.

Ox represents each entry with [`TxEnvelopeTempo.Call`](/tempo/reference/TxEnvelopeTempo/types#txenvelopetempocall)
and serializes the full batch with the surrounding envelope.

[See Batch Calls in the Tempo Transactions documentation](https://docs.tempo.xyz/protocol/transactions#batch-calls)

## Recipes

### Construct a Batch

Pass multiple call objects to
[`TxEnvelopeTempo.from`](/tempo/reference/TxEnvelopeTempo/from). A call may omit `to` for contract
creation, and may omit `data` or `value` when they are not needed.

```ts twoslash
import { TxEnvelopeTempo } from 'ox/tempo'

// [!code focus:start]
const envelope = TxEnvelopeTempo.from({
  // [!code hl:start]
  calls: [
    {
      data: '0xcafebabe00000000000000000000000000000001',
      to: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
    },
    {
      data: '0xdeadbeef00000000000000000000000000000002',
      to: '0xfeedfacefeedfacefeedfacefeedfacefeedface',
    },
  ],
  // [!code hl:end]
  chainId: 4217,
  gas: 200_000n,
  maxFeePerGas: 2_000_000_000n,
  nonce: 0n,
  nonceKey: 1n,
})
// @log: {
// @log:   calls: [{ data: '0xcafebabe...', to: '0xdeadbeef...' }, { data: '0xdeadbeef...', to: '0xfeedface...' }],
// @log:   chainId: 4217,
// @log:   gas: 200000n,
// @log:   type: 'tempo',
// @log:   ...
// @log: }
// [!code focus:end]
```

### Sign and Serialize a Batch

The sender signs one payload for the complete ordered call list. Attach that signature when
calling [`TxEnvelopeTempo.serialize`](/tempo/reference/TxEnvelopeTempo/serialize).

```ts twoslash
import { Secp256k1 } from 'ox'
import { TxEnvelopeTempo } from 'ox/tempo'

// 1. Set up the signing key and ordered batch.
const privateKey = Secp256k1.randomPrivateKey()
const envelope = TxEnvelopeTempo.from({
  calls: [
    {
      data: '0xcafebabe00000000000000000000000000000001',
      to: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
    },
    {
      data: '0xdeadbeef00000000000000000000000000000002',
      to: '0xfeedfacefeedfacefeedfacefeedfacefeedface',
    },
  ],
  chainId: 4217,
  gas: 200_000n,
  maxFeePerGas: 2_000_000_000n,
  nonce: 0n,
  nonceKey: 1n,
})

// [!code focus:start]
// 2. Sign the payload for the complete batch.
const signature = Secp256k1.sign({
  payload: TxEnvelopeTempo.getSignPayload(envelope),
  privateKey,
})

// 3. Serialize the batch with its signature.
const serialized = TxEnvelopeTempo.serialize(envelope, { signature })
// @log: '0x76...'
// [!code focus:end]
```

### Inspect a Serialized Batch

[`TxEnvelopeTempo.deserialize`](/tempo/reference/TxEnvelopeTempo/deserialize) preserves the call
order and decodes each call's target, value, and calldata.

```ts twoslash
import { TxEnvelopeTempo } from 'ox/tempo'

const envelope = TxEnvelopeTempo.from({
  calls: [
    { to: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef' },
    { to: '0xfeedfacefeedfacefeedfacefeedfacefeedface' },
  ],
  chainId: 4217,
})
// [!code focus:start]
const serialized = TxEnvelopeTempo.serialize(envelope)

const { calls } = TxEnvelopeTempo.deserialize(serialized)
// @log: [{ to: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef' }, { to: '0xfeedfacefeedfacefeedfacefeedfacefeedface' }]
// [!code focus:end]
```

## Best Practices

### Preserve Dependency Order

Place setup calls before the operations that depend on them. Reordering the array changes the
sign payload and may change execution behavior.

### Estimate the Entire Batch

Gas belongs to the envelope, not to individual call entries. Estimate the complete ordered batch
and include enough gas for all calls.

### Treat the Batch as One Failure Boundary

Do not design recovery logic around a partial batch. A successful receipt represents the whole
batch, while a revert discards its state changes.

## See More

<Cards>
  <Card icon="lucide:send" title="Transaction Envelopes" description="Construct, sign, serialize, and submit Tempo envelopes." to="/tempo/guides/transaction-envelopes" />

  <Card icon="lucide:split" title="Concurrent Transactions" description="Use independent nonce keys for parallel submission." to="/tempo/guides/transaction-envelopes/concurrent-transactions" />

  <Card icon="lucide:book-open" title="Viem: Batch Calls" description="Build and submit atomic call batches with a Viem client." to="https://viem.sh/tempo/guides/batch-calls" />
</Cards>
