ZKsync Wallet Integration Guide for Developers

·

The ZKsync Wallet module is a powerful tool for developers building on the ZKsync Era network. It enables seamless integration, creation, and management of Ethereum-compatible wallets with support for both L1 (Ethereum) and L2 (ZKsync) operations. Whether you're depositing assets, checking balances, or executing cross-chain transactions, this guide walks you through essential wallet functions with practical code examples.

Designed with developer efficiency in mind, the Wallet object extends from BaseAccount, offering a comprehensive interface for interacting with ZKsync’s Layer 2 infrastructure. This makes it ideal for dApp developers aiming to enhance user experience through faster transactions and reduced gas fees.

Core Wallet Initialization

To begin working with the ZKsync Wallet, instantiate the Wallet object using three key components:

For testing purposes, burner wallets are recommended to avoid exposing real private keys and reduce security risks during development.

👉 Discover how to securely manage blockchain interactions using advanced tools

from eth_account import Account
from web3 import Web3
from zksync2.account.wallet import Wallet
from zksync2.module.module_builder import ZkSyncBuilder

ZKSYNC_PROVIDER = "https://sepolia.era.zksync.dev"
ETH_PROVIDER = "https://rpc.ankr.com/eth_sepolia"

zk_web3 = ZkSyncBuilder.build(ZKSYNC_PROVIDER)
eth_web3 = Web3(Web3.HTTPProvider(ETH_PROVIDER))
account = Account.from_key("PRIVATE_KEY")
wallet = Wallet(zk_web3, eth_web3, account)

Key Wallet Functions and Use Cases

Accessing Smart Contracts

The main_contract property returns the ZKsync smart contract wrapper, enabling direct interaction with core protocol features.

contract = wallet.main_contract
print(contract.address)

Similarly, get_l1_bridge_contracts() and get_l2_bridge_contracts() provide access to bridge contracts used for asset transfers between chains. Note that ETH bridging uses the main contract rather than a separate Ether bridge.

Balance Management Across Layers

Use the following methods to check token balances:

These functions are critical for real-time balance display in decentralized applications.

l2_balance = wallet.get_balance()
l1_balance = wallet.get_l1_balance()
all_balances = wallet.get_all_balances()

Token Address Mapping

Since token addresses differ between L1 and L2, use l2_token_address(l1_address) to retrieve the correct L2 equivalent. This ensures accurate token handling when bridging assets.

l2_eth_address = wallet.l2_token_address("0x...")  # L1 token address

Cross-Chain Transactions: Deposit & Withdrawal

Depositing Assets to L2

The deposit() method transfers ETH or ERC20 tokens from Ethereum to ZKsync. For ERC20s, approval via approve_erc20() is required unless sufficient allowance exists.

Before initiating a deposit, estimate costs using:

from zksync2.core.types import DepositTransaction

tx_hash = wallet.deposit(
    DepositTransaction(token="0x...", amount=5, to=wallet.address)
)

For failed deposits, use claimFailedDeposit(depositHash) to reclaim funds stuck due to L2 finalization issues.

Withdrawing from L2 to L1

Initiate withdrawals using withdraw(). Finalize them after the challenge period with finalizeWithdrawal(withdraw_hash).

Check finalization status with:

is_finalized = wallet.is_withdrawal_finalized("0x...")

👉 Learn how top developers optimize cross-chain transaction workflows


Advanced Features

Paymaster Integration

ZKsync supports meta-transactions where fees are paid in ERC20 tokens instead of ETH. Use paymaster_params in transfer or withdrawal calls to enable gasless experiences for users.

paymaster_params = PaymasterParams(
    paymaster="0xPaymasterAddress",
    paymaster_input=encoder.encode_approval_based(token_address, fee_amount)
)

wallet.transfer(TransferTransaction(..., paymaster_params=paymaster_params))

Requesting L2 Execution from L1

Use requestExecute() to trigger L2 contract calls from L1. This is useful for dApps requiring trustless communication across layers.

Estimate execution cost with estimateGasRequestExecute(), and build unsigned transactions using get_request_execute_transaction().


Utility Methods


Frequently Asked Questions (FAQ)

Q: What is the difference between get_balance() and get_l1_balance()?
A: get_balance() checks funds on ZKsync (L2), while get_l1_balance() queries the wallet’s balance on Ethereum (L1).

Q: Do I need to manually approve every ERC20 deposit?
A: Only if the token hasn’t been approved before. Use get_allowance_l1(token) to check existing allowances and avoid redundant approvals.

Q: Can I use this SDK on mainnet?
A: Yes, but replace Sepolia testnet URLs with mainnet RPC endpoints and ensure proper key management.

Q: How long does a withdrawal take?
A: Withdrawals require a 7-day challenge period on zkSync Era before finalization via finalizeWithdrawal.

Q: Is there a way to simulate a transaction before sending?
A: Use estimate_gas_deposit() and get_full_required_deposit_fee() to preview costs and behavior without executing.

Q: What happens if my deposit fails?
A: You can reclaim funds using claimFailedDeposit() if the L2 transaction fails during finalization.


Final Thoughts

Mastering the ZKsync Wallet module empowers developers to build scalable, user-friendly dApps leveraging Layer 2 scalability. From secure initialization to advanced cross-chain logic, these tools streamline development while maintaining Ethereum-grade security.

Whether you're building DeFi platforms, NFT marketplaces, or Web3 games, understanding these core functionalities ensures robust integration with the ZKsync ecosystem.

👉 Start building high-performance dApps with next-gen blockchain tools