> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://viem-pqgo0xlqv-wevm.vercel.app/api/mcp` to find what you need.

# Deposit to a Zone

## Overview

Funds enter a zone by depositing them from Tempo Mainnet into the zone's contract. The deposit is
submitted on Mainnet against the L1 client, and the corresponding balance appears inside the zone once
the deposit is processed. The current ZonePortal protocol encrypts the recipient and memo before
submitting the deposit.

[See the Zone Bridging specification](https://docs.tempo.xyz/protocol/zones/bridging)

:::warning
Tempo Zones are in early development and available on Tempo Testnet only. Expect breaking changes and
do not use them in production.
:::

## Recipes

These recipes assume you have [set up a Tempo client](/tempo) for Mainnet and
[connected to a zone](/tempo/guides/zones/connect).

### Deposit to a Zone

Deposit a TIP-20 token from your Mainnet balance with
[`zone.encryptedDepositSync`](/tempo/actions/zone.encryptedDeposit). The deposit runs on Mainnet, and
the recipient and memo are decryptable only by the zone operator.

:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'

const { receipt } = await client.zone.encryptedDepositSync({
  amount: parseUnits('100', 6),
  token: '0x20c0000000000000000000000000000000000001',
  zoneId: 7,
})
```

```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::

### Confirm Zone Import

After depositing, call [`zone.waitForTempoBlock`](/tempo/actions/zone.waitForTempoBlock) with the deposit receipt block number. The action resolves once the zone has imported that Tempo block. Then read the recipient balance inside the zone.

:::code-group
```ts twoslash [example.ts]
import { client } from './zones.config'

const info = await client.zone.waitForTempoBlock({
  tempoBlockNumber: 123456n,
})
```

```ts twoslash [zones.config.ts] filename="zones.config.ts"
// [!include ~/snippets/tempo/zones.config.ts:setup]
```
:::

### Read Deposit Outcomes

After the zone imports a Tempo block, use [`getContractEvents`](/docs/contract/getContractEvents)
with `Abis.zoneInbox` and `Addresses.zoneInbox` to read its deposit outcome events. The inbox
`depositHash` is the running queue hash emitted as `newCurrentDepositQueueHash` by the portal's
`DepositMade` event for that deposit, including the earlier queue entries.

Extract that hash from the parent-chain receipt with [`parseEventLogs`](/docs/contract/parseEventLogs)
and filter inbox outcomes by it. Importing a block alone does not establish that its deposits were
credited.

:::code-group
```ts twoslash [example.ts]
import { parseEventLogs } from 'viem'
import { getContractEvents } from 'viem/actions'
import { Abis, Addresses } from 'viem/tempo'
import { client as parentClient } from './viem.config'
import { client as zoneClient } from './zones.config'

const { receipt } = await parentClient.zone.encryptedDepositSync({
  amount: 1_000_000n,
  token: '0x20c0000000000000000000000000000000000001',
  zoneId: 7,
})
if (receipt.status === 'pending') throw new Error('Deposit is pending.')

const [deposit] = parseEventLogs({
  abi: Abis.zonePortal,
  eventName: 'DepositMade',
  logs: receipt.logs,
  strict: true,
})
if (!deposit) throw new Error('DepositMade event not found.')

await zoneClient.zone.waitForTempoBlock({
  tempoBlockNumber: receipt.blockNumber,
})
const depositHash = deposit.args.newCurrentDepositQueueHash
const outcomes = await getContractEvents(zoneClient, {
  address: Addresses.zoneInbox,
  abi: Abis.zoneInbox,
  args: { depositHash },
  fromBlock: 0n,
})
const outcome = outcomes.find((log) =>
  log.eventName === 'DepositProcessed' ||
  log.eventName === 'DepositFailed' ||
  log.eventName === 'DepositRejected',
)
```

```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```

```ts twoslash [zones.config.ts] filename="zones.config.ts"
// [!include ~/snippets/tempo/zones.config.ts:setup]
```
:::

## Best Practices

### Deposit on Mainnet, Read on the Zone

Deposits are L1 actions sent with your Mainnet client, while outcome events and balance reads come
from the zone client. Keep both clients configured so you can submit a deposit and then check its
processing result.

### Prepare Private Details Before Broadcasting

If another wallet or service will broadcast the deposit, use
[`zone.encryptedDeposit.prepare`](/tempo/actions/zone.encryptedDeposit#prepared-usage) to encrypt the
private recipient and memo first. The broadcaster can pass the returned payload directly to
[`zone.encryptedDeposit`](/tempo/actions/zone.encryptedDeposit) without learning the private details.
Validate the public transaction details before broadcasting a prepared payload from another party.

## See More

<Cards>
  <Card icon="lucide:plug" title="Connect to a Zone" description="Authenticate a Viem client with a zone before reading state." to="/tempo/guides/zones/connect" />

  <Card icon="lucide:arrow-up-from-line" title="Withdraw from a Zone" description="Move stablecoins from a zone back to Tempo Mainnet." to="/tempo/guides/zones/withdraw" />

  <Card icon="lucide:square-function" title="zone.encryptedDeposit" description="Deposit a TIP-20 token from Mainnet into a zone." to="/tempo/actions/zone.encryptedDeposit" />

  <Card icon="lucide:book-open" title="Tempo Docs: Zone Bridging" description="How deposits and withdrawals move between Mainnet and zones." to="https://docs.tempo.xyz/protocol/zones/bridging" />
</Cards>
