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

# EthersClient

> Low-level client for the Ethers adapter. Carries providers/signer, resolves core contract addresses, and exposes connected ethers.Contract instances.

## At a glance

* **Factory:** `createEthersClient({ l1, l2, signer, overrides? }) → EthersClient`
* **What it provides:** cached core **addresses**, connected **contracts**, L2-bound **ZKsync RPC** (`zks`), and a signer force-bound to **L1**.
* **When to use:** create this first; then pass into `createEthersSdk(client)`.

## Import

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
import { createEthersClient } from '@dutterbutter/zksync-sdk/ethers';
```

## Quick start

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
import { JsonRpcProvider, Wallet } from 'ethers';
import { createEthersClient } from '@dutterbutter/zksync-sdk/ethers';

const l1 = new JsonRpcProvider(process.env.ETH_RPC!);
const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!);
const signer = new Wallet(process.env.PRIVATE_KEY!, l1);

const client = createEthersClient({ l1, l2, signer });

// Resolve core addresses (cached)
const addrs = await client.ensureAddresses();

// Connected contracts
const { bridgehub, l1AssetRouter } = await client.contracts();
```

<Tip>
  The signer is force-bound to the **L1** provider to make L1 finalization flows work out of the
  box.
</Tip>

## `createEthersClient(args) → EthersClient`

<ParamField name="args.l1" type="ethers.AbstractProvider" required>
  L1 provider for reads and L1 transactions.
</ParamField>

<ParamField name="args.l2" type="ethers.AbstractProvider" required>
  L2 (ZKsync) provider for reads and ZK RPC.
</ParamField>

<ParamField name="args.signer" type="ethers.Signer" required>
  Signer for sends. If not connected to <code>args.l1</code>, it will be connected.
</ParamField>

<ParamField name="args.overrides" type="Partial<ResolvedAddresses>">
  Optional address overrides (forks/tests).
</ParamField>

**Returns:** `EthersClient`

## EthersClient interface

<ResponseField name="kind" type="'ethers'">
  Adapter discriminator.
</ResponseField>

<ResponseField name="l1" type="ethers.AbstractProvider">
  Public L1 provider.
</ResponseField>

<ResponseField name="l2" type="ethers.AbstractProvider">
  Public L2 (ZKsync) provider.
</ResponseField>

<ResponseField name="signer" type="ethers.Signer">
  Signer (bound to <code>l1</code> for sends).
</ResponseField>

<ResponseField name="zks" type="ZksRpc">
  ZKsync-specific RPC surface bound to <code>l2</code>.
</ResponseField>

## Methods

### `ensureAddresses() → Promise<ResolvedAddresses>`

Resolve and cache core contract addresses from chain state (merges any `overrides`).

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
const a = await client.ensureAddresses();
/*
{
  bridgehub, l1AssetRouter, l1Nullifier, l1NativeTokenVault,
  l2AssetRouter, l2NativeTokenVault, l2BaseTokenSystem
}
*/
```

### `contracts() → Promise<{ ...contracts }>`

Return connected `ethers.Contract` instances for all core contracts.

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
const c = await client.contracts();
const bh = c.bridgehub; // call bh.getAddress(), bh.interface, bh.functions.*, etc.
```

### `refresh(): void`

Clear cached addresses/contracts. Subsequent calls re-resolve.

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
client.refresh();
await client.ensureAddresses();
```

### `baseToken(chainId: bigint) → Promise<Address>`

Return the **L1 base-token address** for a given L2 chain via `Bridgehub.baseToken(chainId)`.

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
const base = await client.baseToken(324n /* e.g., Era */);
```

## Types

### `ResolvedAddresses`

```ts theme={"theme":{"light":"vitesse-light","dark":"tokyo-night"}}
type ResolvedAddresses = {
  bridgehub: Address;
  l1AssetRouter: Address;
  l1Nullifier: Address;
  l1NativeTokenVault: Address;
  l2AssetRouter: Address;
  l2NativeTokenVault: Address;
  l2BaseTokenSystem: Address;
};
```

## Notes & pitfalls

* **Provider roles:** `l1` is used for L1 lookups and finalization sends; `l2` is used for ZKsync reads/RPC via `zks`.
* **Signer binding:** The signer is connected to `l1` to ensure L1 transactions (e.g., finalize) succeed without extra wiring.
* **Caching:** `ensureAddresses()` and `contracts()` are cached. Call `refresh()` after network changes or when using new overrides.
* **Overrides:** For forks or custom deployments, pass `overrides` at construction; they are merged with on-chain resolution.
