# Getting started
In this tutorial we will demonstrate how to:
- Connect to the zkSync network.
- Deposit assets from Ethereum into zkSync.
- Make transfers.
- Withdraw funds back to Ethereum mainnet.
# Installation
ZkSyncSDK can be installed (preferably in a virtualenv) using pip as follows:
pip install git+https://github.com/zksync-sdk/zksync-python.git
Unfortunately, currently, SDK is not published on PyPI, thus installation through the git repository is the only option.
# Setup crypto library
For using this library:
- You have to download zksync-crypto-library from https://github.com/zksync-sdk/zksync-crypto-c/releases (opens new window)
- Set env variable
ZK_SYNC_LIBRARY_PATH
with a path to the downloaded library
# Initialize crypto library
from zksync_sdk import ZkSyncLibrary
lib = ZkSyncLibrary()
# Connecting to zkSync network
To interact with zkSync network users need to know the endpoint of the operator node.
from zksync_sdk import HttpJsonRPCTransport, ZkSyncProviderV01, network
provider = ZkSyncProviderV01(provider=HttpJsonRPCTransport(network=network.goerli))
# Ethereum signer
Ethereum signer is mandatory for sending both L1 and L2 transactions since L2 transactions require an Ethereum signature as a part of 2-factor authentication scheme. It is possible to create a wallet without an Ethereum private key, but such a wallet will only be able to perform read requests to the zkSync server.
Ethereum signer is represented by the EthereumSignerInterface
abstract class from
zksync_sdk.ethereum_signer.interface
.
By default, there is an implementation for web3 signer.
from zksync_sdk import EthereumSignerWeb3
from web3 import Account
account = Account.from_key("PRIVATE_KEY")
ethereum_signer = EthereumSignerWeb3(account=account)
# Creating a Wallet
To control your account in zkSync, use the Wallet
object. It can sign transactions with keys stored in ZkSyncSigner
and send a transaction to zkSync network using ZkSyncProviderInterface
.
To create a Wallet
object, you have to initialize ZkSyncSigner
from web3 import Account
from zksync_sdk import ZkSyncSigner, network, ZkSyncLibrary
library = ZkSyncLibrary()
# Initialization from ethereum private key
account = Account.from_key("PRIVATE_KEY")
signer_v1 = ZkSyncSigner.from_account(account, library, network.goerli.chain_id)
# Initialization from zksync seed
signer_v2 = ZkSyncSigner.from_seed(library, b"seed")
# Initialization from zksync private key
signer_v3 = ZkSyncSigner(library, b"private_key")
For creating Wallet
we have to create: EthereumProvider
, ZkSyncLibrary
, ZkSyncProvider
, EthereumSigner
,
ZkSyncSigner
.
from web3 import Web3, HTTPProvider, Account
from zksync_sdk import ZkSyncProviderV01, HttpJsonRPCTransport, network, ZkSync, EthereumProvider, Wallet, ZkSyncSigner, EthereumSignerWeb3, ZkSyncLibrary
# Load crypto library
library = ZkSyncLibrary()
# Create Zksync Provider
provider = ZkSyncProviderV01(provider=HttpJsonRPCTransport(network=network.goerli))
# Setup web3 account
account = Account.from_key("PRIVATE_KEY")
# Create EthereumSigner
ethereum_signer = EthereumSignerWeb3(account=account)
# Load contract addresses from server
contracts = await provider.get_contract_address()
# Setup web3
# NOTE: Please ensure that the web3 provider and zksync provider match.
# A mainnet web3 provider paired with a testnet zksync provider will transact on mainnet!!
w3 = Web3(HTTPProvider(endpoint_uri="GETH_ENDPOINT" ))
# Setup zksync contract interactor
zksync = ZkSync(account=account, web3=w3,
zksync_contract_address=contracts.main_contract)
# Create ethereum provider for interacting with ethereum node
ethereum_provider = EthereumProvider(w3, zksync)
# Initialize zksync signer, all creating options were described earlier
signer = ZkSyncSigner.from_account(account, library, network.goerli.chain_id)
# Initialize Wallet
wallet = Wallet(ethereum_provider=ethereum_provider, zk_signer=signer,
eth_signer=ethereum_signer, provider=provider)
# Depositing assets from Ethereum into zkSync
Depositing requires Wallet
object to be created with access to the Ethereum signer.
We are going to deposit 1.0 USDT
to our zkSync account.
from decimal import Decimal
# Find token for depositing
token = await wallet.resolve_token("USDT")
# Approve Enough deposit using token contract
await wallet.ethereum_provider.approve_deposit(token, Decimal(1))
# Deposit money from contract to our address
deposit = await wallet.ethereum_provider.deposit(token, Decimal(1),
account.address)
You don't need to approve a deposit to transfer ETH.
# Unlocking zkSync account
To control assets in zkSync network, an account must register a separate public key once.
from zksync_sdk.types import ChangePubKeyEcdsa
if not await wallet.is_signing_key_set():
tx = await wallet.set_signing_key("ETH", eth_auth_data=ChangePubKeyEcdsa())
status = await tx.await_committed()
# Checking zkSync account balance
# Committed state is not final yet
committedETHBalance = await wallet.get_balance("ETH", "committed")
# Verified state is final
verifiedETHBalance = await wallet.get_balance("ETH", "verified")
To list all tokens of this account at once, use get_account_state
:
account_state = await wallet.get_account_state()
committed_eth_balance = account_state.committed.balances.get("ETH")
verified_dai_balance = account_state.verified.balances.get("DAI")
# Making a transfer in zkSync
For making transfer to another account you just need to set receiver amount and token
from decimal import Decimal
tx = await wallet.transfer("0x21dDF51966f2A66D03998B0956fe59da1b3a179F",
amount=Decimal("0.01"), token="USDC")
status = await tx.await_committed()
If you want more control over the transaction, you can optionally provide nonce
and fee
# Swapping tokens
To swap tokens, first call the get_order
or get_limit_order
method on a wallet, to create and sign an order.
When 2 signed orders are collected, they can be submitted by anyone using the swap
method.
from fractions import Fraction
from decimal import Decimal
from zksync_sdk.types import RatioType
orderA = await walletA.get_order('USDT', 'ETH', Fraction(1500, 1), RatioType.token, Decimal('10.0'))
orderB = await walletB.get_order('ETH', 'USDT', Fraction(1, 1200), RatioType.token, Decimal('0.007'))
tx = await submitter.swap((orderA, orderB), 'ETH')
status = await tx.await_committed()
For detailed information, visit Swaps tutorial or API reference.
# Withdrawing funds back to Ethereum
from decimal import Decimal
tx = await wallet.withdraw("0x21dDF51966f2A66D03998B0956fe59da1b3a179F",
Decimal("0.001"), "USDT")
status = await tx.await_committed()
Assets will be withdrawn to the target wallet after the zero-knowledge proof of zkSync block with this operation is generated and verified by the mainnet contract.
# NFTs
For detailed information, visit the NFT tutorial.
# Minting
To mint an NFT, provide a 32-byte content hash, recipient address and token which will be used to pay fees.
tx = await wallet.mint_nft("0x0000000000000000000000000000000000000000000000000000000000000123",
"0x21dDF51966f2A66D03998B0956fe59da1b3a179F", "USDC")
status = await tx.await_committed()
Note that before transfering or withdrawing a freshly-minted NFT, this operation has to be verified (not just committed).
# Checking owned and minted NFTs
To check your minted NFTs, use nfts
and minted_nfts
fields on the committed or verified account state.
account_state = await wallet.get_account_state()
owned_nfts = account_state.committed.nfts
# Minted nfts can only be used after verification of the mint_nft transaction
minted_nfts = account_state.verified.minted_nfts
# Transfering
To transfer an NFT, provide address to transfer to, NFT itself and token which will be used to pay fees.
await self.wallet.transfer_nft("0x995a8b7f96cb837533b79775b6209696d51f435c", first_value, "USDC")
# Withdrawing
To withdraw an NFT, provide address to withdraw to, NFT itself and token which will be used to pay fees.
tx = await wallet.withdraw_nft("0x21dDF51966f2A66D03998B0956fe59da1b3a179F", nft, "USDC")
status = await tx.await_committed()
# Getting information about zkSync transaction
For getting information about tx we have to use ZkSyncProviderV01
from zksync_sdk import ZkSyncProviderV01, HttpJsonRPCTransport, network
zk_sync_provider = ZkSyncProviderV01(provider=HttpJsonRPCTransport(network=network.goerli))
tx = await zk_sync_provider.get_tx_receipt("0x95358fcedf9debc24121261d0c508eece61f8f20dfc36b1e5dbe3d33841b30fd")
# Waiting for transaction commitment and finalization
To wait for transaction commitment into a zkSync block, use
await tx.await_committed()
To wait for transaction finalization on L1, use
await tx.await_verified()
# Supporting Two-Factor Authentication for Wallet
Two factor authentification is an additional protection layer enforced by zkSync server. You can read more about it here.
The 2FA can be turned on or turned off using the following methods of the Wallet
class:
- enable_2fa
- disable_2fa
Both methods return True
in case of success and False
otherwise. Example:
# Enable 2FA
result = await self.wallet.enable_2fa()
if result:
account_state = await self.wallet.get_account_state()
# here account_state.account_type == AccountTypes.OWNED
# Disable 2FA but only to a specific pub_key_hash
# If you want to disable 2FA for the account entirely, then simply don't provide the `pub_key_hash`
pub_key_hash = self.wallet.zk_signer.pubkey_hash_str()
result = await self.wallet.disable_2fa(pub_key_hash)
if result:
account_state = await self.wallet.get_account_state()
# here account_state.account_type == AccountTypes.No2FA