> ## Documentation Index
> Fetch the complete documentation index at: https://zksync-sdk.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Deposits

> L1 → L2 deposits for ETH and ERC-20 with quote, prepare, create, status, and wait helpers (Viem adapter).

## At a glance

* **Resource:** `sdk.deposits`
* **Most common flow:** `quote → create → wait({ for: 'l2' })`
* **Auto-routing:** ETH vs ERC-20 and base-token vs non-base handled internally
* **Error style:** Throwing methods (`quote`, `prepare`, `create`, `wait`) + result variants (`tryQuote`, `tryPrepare`, `tryCreate`, `tryWait`)

## Import

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
import {
  createPublicClient,
  createWalletClient,
  http,
  parseEther,
  type Account,
  type Chain,
  type Transport,
  type WalletClient,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem';

const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`);
const l1 = createPublicClient({ transport: http(L1_RPC) });
const l2 = createPublicClient({ transport: http(L2_RPC) });
const l1Wallet: WalletClient<Transport, Chain, Account> = createWalletClient({
  account,
  transport: http(L1_RPC),
});

// --- 2. Initialize the SDK ---
const client = createViemClient({ l1, l2, l1Wallet });
const sdk = createViemSdk(client);
// sdk.deposits → DepositsResource
```

## Quick start

Deposit **0.1 ETH** from L1 → L2 and wait for **L2 execution**:

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
const handle = await sdk.deposits.create({
  token: ETH_ADDRESS, // 0x…00 for ETH
  amount: parseEther('0.1'),
  to: await signer.getAddress(),
});

const l2Receipt = await sdk.deposits.wait(handle, { for: 'l2' }); // null only if no L1 hash
```

<Tip>
  For UX that never throws, use the <code>try\*</code> variants and branch on <code>ok</code>.
</Tip>

## Route selection (automatic)

* `eth-base` — ETH when L2 base token **is ETH**
* `eth-nonbase` — ETH when L2 base token **≠ ETH**
* `erc20-base` — ERC-20 that **is** the L2 base token
* `erc20-nonbase` — ERC-20 that **is not** the L2 base token

You **do not** pass a route; it’s derived from network metadata + `token`.

## Method reference

### `quote(p: DepositParams) → Promise<DepositQuote>`

Estimate the operation (route, approvals, gas hints). Does **not** send txs.

<ParamField name="p.token" type="Address" required>
  L1 token (use <code>0x…00</code> for ETH).
</ParamField>

<ParamField name="p.amount" type="bigint" required>
  Amount in wei.
</ParamField>

<ParamField name="p.to" type="Address" required>
  L2 recipient.
</ParamField>

**Returns:** `DepositQuote`

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
const q = await sdk.deposits.quote({
  token: ETH_L1,
  amount: parseEther('0.25'),
  to: await signer.getAddress(),
});
/*
{
  route: "eth-base" | "eth-nonbase" | "erc20-base" | "erc20-nonbase",
  approvalsNeeded: [{ token, spender, amount }],
  baseCost?: bigint,
  mintValue?: bigint,
  suggestedL2GasLimit?: bigint,
  gasPerPubdata?: bigint
}
*/
```

<Tip>
  If <code>approvalsNeeded</code> is non-empty (ERC-20), <code>create</code> will include those
  steps automatically.
</Tip>

### `tryQuote(p) → Promise<{ ok: true; value: DepositQuote } | { ok: false; error }>`

Result-style `quote`.

### `prepare(p: DepositParams) → Promise<DepositPlan<TransactionRequest>>`

Builds the plan (ordered steps + unsigned txs) without sending.

**Returns:** `DepositPlan`

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
const plan = await sdk.deposits.prepare({ token: ETH_L1, amount: parseEther('0.05'), to });
/*
{
  route,
  summary: DepositQuote,
  steps: [
    { key: "approve:USDC", kind: "approve", tx: TransactionRequest },
    { key: "bridge",       kind: "bridge",  tx: TransactionRequest }
  ]
}
*/
```

### `tryPrepare(p) → Promise<{ ok: true; value: DepositPlan } | { ok: false; error }>`

Result-style `prepare`.

### `create(p: DepositParams) → Promise<DepositHandle<TransactionRequest>>`

Prepares and **executes** all required L1 steps. Returns a handle (with L1 tx hash and per-step hashes).

**Returns:** `DepositHandle`

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
const handle = await sdk.deposits.create({ token, amount, to });
/*
{
  kind: "deposit",
  l1TxHash: Hex,
  stepHashes: Record<string, Hex>,
  plan: DepositPlan
}
*/
```

<Warning>
  If any step reverts, <code>create</code> throws a typed error. Prefer <code>tryCreate</code> to
  avoid exceptions.
</Warning>

### `tryCreate(p) → Promise<{ ok: true; value: DepositHandle } | { ok: false; error }>`

Result-style `create`.

### `status(handleOrHash) → Promise<DepositStatus>`

Resolve current phase for a deposit. Accepts the `DepositHandle` from `create` **or** a raw L1 tx hash.

**Phases**

* `UNKNOWN` — no L1 hash provided
* `L1_PENDING` — L1 receipt not yet found
* `L1_INCLUDED` — included on L1; L2 hash not derivable yet
* `L2_PENDING` — L2 hash known; waiting for L2 receipt
* `L2_EXECUTED` — L2 receipt found with `status === 1`
* `L2_FAILED` — L2 receipt found with `status !== 1`

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
const s = await sdk.deposits.status(handle);
// { phase, l1TxHash, l2TxHash? }
```

### `wait(handleOrHash, { for: 'l1' | 'l2' }) → Promise<TransactionReceipt | null>`

Block until the chosen checkpoint.

* `{ for: 'l1' }` → L1 receipt (or `null` if no L1 hash available)
* `{ for: 'l2' }` → L2 receipt after canonical execution (or `null` if no L1 hash)

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
const l1Receipt = await sdk.deposits.wait(handle, { for: 'l1' });
const l2Receipt = await sdk.deposits.wait(handle, { for: 'l2' });
```

### `tryWait(handleOrHash, opts) → Result<TransactionReceipt>`

Result-style `wait`.

## End-to-end examples

### ETH deposit (typical)

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
const handle = await sdk.deposits.create({
  token: ETH_ADDRESS,
  amount: parseEther('0.1'),
  to: await signer.getAddress(),
});

await sdk.deposits.wait(handle, { for: 'l2' });
```

### ERC-20 deposit (with automatic approvals)

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
const handle = await sdk.deposits.create({
  token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // example: USDC
  amount: 1_000_000n, // 1.0 USDC (6 dp)
  to: await signer.getAddress(),
});

const l1Receipt = await sdk.deposits.wait(handle, { for: 'l1' });
```

## Types (overview)

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
type DepositParams = {
  token: Address; // 0x…00 for ETH
  amount: bigint; // wei
  to: Address; // L2 recipient
};

type DepositQuote = {
  route: 'eth-base' | 'eth-nonbase' | 'erc20-base' | 'erc20-nonbase';
  approvalsNeeded: Array<{ token: Address; spender: Address; amount: bigint }>;
  baseCost?: bigint;
  mintValue?: bigint;
  suggestedL2GasLimit?: bigint;
  gasPerPubdata?: bigint;
};

type DepositPlan<TTx = TransactionRequest> = {
  route: DepositQuote['route'];
  summary: DepositQuote;
  steps: Array<{ key: string; kind: string; tx: TTx }>;
};

type DepositHandle<TTx = TransactionRequest> = {
  kind: 'deposit';
  l1TxHash: Hex;
  stepHashes: Record<string, Hex>;
  plan: DepositPlan<TTx>;
};

type DepositStatus =
  | { phase: 'UNKNOWN'; l1TxHash: Hex }
  | { phase: 'L1_PENDING'; l1TxHash: Hex }
  | { phase: 'L1_INCLUDED'; l1TxHash: Hex }
  | { phase: 'L2_PENDING'; l1TxHash: Hex; l2TxHash: Hex }
  | { phase: 'L2_EXECUTED'; l1TxHash: Hex; l2TxHash: Hex }
  | { phase: 'L2_FAILED'; l1TxHash: Hex; l2TxHash: Hex };
```

<Tip>
  Prefer the <code>try\*</code> variants if you want to avoid exceptions and work with result
  objects.
</Tip>

## Notes & pitfalls

* **ETH sentinel:** use the canonical `0x…00` address when passing ETH as `token`.
* **Receipts timing:** `wait({ for: 'l2' })` resolves on canonical L2 execution; it can take longer than L1 inclusion.
* **Gas hints:** `suggestedL2GasLimit` and `gasPerPubdata` are hints; advanced users may override via low-level calls from the plan.
