Skip to main content

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

Quick start

The signer is force-bound to the L1 provider to make L1 finalization flows work out of the box.

createEthersClient(args) → EthersClient

Returns: EthersClient

EthersClient interface

'ethers'
Adapter discriminator.
ethers.AbstractProvider
Public L1 provider.
ethers.AbstractProvider
Public L2 (ZKsync) provider.
ethers.Signer
Signer (bound to l1 for sends).
ZksRpc
ZKsync-specific RPC surface bound to l2.

Methods

ensureAddresses() → Promise<ResolvedAddresses>

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

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

Return connected ethers.Contract instances for all core contracts.

refresh(): void

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

baseToken(chainId: bigint) → Promise<Address>

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

Types

ResolvedAddresses

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.