Argent Login on zkSync Era


Why Argent Login?

We created Argent Login to provide the best interaction between a browser dapp and Argent mobile wallet.

Who is it for?

Argent Login is currently available to any dapp developers building on zkSync Era (2.0).
Integrating Argent Login to your dapp will ensure that Argent users can effortlessly interact with your browser dapp.
Thanks to native account abstraction support on zkSync Era, we are building the most secure and simple wallet experience (seedless recovery, fraud monitoring, etc.). This is why Argent Login is focused on zkSync Era. This tutorial will explain how to make sure your dapp is 100% compatible with Argent wallet. NOTE: zkSync Era is currently on Fair Onboarding Alpha.

Get started

Install an Argent test build on your mobile phone

The private key of an Argent wallet is stored on mobile, so you'll need a mobile device with our beta app to test the integration:
(note: these builds are running on Goerli testnet)
When setting up your wallet, you do NOT need to provide a phone number: tap on Can't receive text messages.
If you use Gmail, you can include the + character before the @ sign to simulate a different email address, for example: use [email protected] to fake a new address and still receive emails in [email protected].
The default pin code is 111111.
Once your wallet is created, you may have to tap on the network selector at the top left, then tap the + icon, and add the zkSync Era account.

Account abstraction

Account abstraction means that the dapp doesn't need to know which wallet it is interacting with. Everything should be transparent for the dapp developer if all of the necessary precautions have been taken. See the section below for more information.

Add Argent Login in your "connect wallet" options

There are many options for integrating Argent to a dapp:

Getting started with Web3-onboard

The following assumes you're familiar with Web3-onboard and your dapp already uses it. If not, you can begin with their tutorial here:
Install the dependencies:
yarn add @argent/login @web3-onboard/core @web3-onboard/[email protected]/web3-onboard-argent
You can now add the argent module to your Web3-onboard configuration object, and make sure you declare the zkSync chain.
import Onboard from "@web3-onboard/core";
import argentModule from "@web3-onboard/argent";
// initialize the module
const argent = argentModule();
const onboard = Onboard({
// ... other Onboard options
wallets: [
// ... other wallets
chains: [
id: "0x118", // = 280
token: "ETH",
label: "zkSync Goerli",
rpcUrl: "",
// ... other chains
const connectedWallets = await onboard.connectWallet();
You should now see the Argent option when connecting to your dapp:

Getting started with React

You can add a ready-made "Log in with Argent" button to your project.
Install the dependency:
yarn add @argent/login-react
Starter code using the component:
import React, { FC, useState } from "react";
import { ethers } from "ethers";
import { ArgentLoginButton, IEthereumProvider } from "@argent/login-react";
export const App: FC = () => {
const [provider, setProvider] = useState<ethers.providers.Web3Provider>();
const handleConnect = async (ethereumProvider: IEthereumProvider) => {
const provider = new ethers.providers.Web3Provider(ethereumProvider);
const handleDisconnect = async () => {
localStorage.removeItem("walletconnect"); // to make sure WC is disconnected
return (
{!provider ? (
chainId: 280,
rpcUrl: "",
) : (
<h2>Connected as {provider.getSigner()._address}</h2>
<button onClick={handleDisconnect}>Disconnect</button>
If you're starting from a brand new create-react-app project with version >= 5.0, you may need to run:
yarn add buffer
And then add:
import { Buffer } from "buffer";
window.Buffer = Buffer;

Getting started with vanilla JavaScript

If you're not using a standard onboarding library, are not developing with React or need to customize the connection experience, you can use the core JavaScript package which will give you access to the EIP-1193 Ethereum Provider object.
Install the dependency:
yarn add @argent/login
Basic connection:
import { getEthereumProvider } from "@argent/login";
const ethereumProvider = await getEthereumProvider({
chainId: 280,
rpcUrl: "",
walletConnect: {
metadata: {
name: "Cool dapp",
description: "Description of a cool dapp",
url: "",
icons: [""]
await ethereumProvider.enable();
Usage with zksync-web3(recommended):
import * as zksync from "zksync-web3";
const provider = new zksync.Web3Provider(ethereumProvider);
await provider.getSigner().sendTransaction(...);
Usage with ethers.js:
import { ethers } from "ethers";
const provider = new ethers.providers.Web3Provider(ethereumProvider);
await provider.getSigner().sendTransaction(...);

Important considerations

Issues with Brave, Safari & ad blockers

One of the great benefits of using Argent Login is that users need to scan a QR code only once and can then connect to any dapp easily. This is enabled by localStorage access via iframes, however, some browsers block this.
If you believe most of your users are Brave & Safari users, you can enable this setting which will fix the issue:
const ethereumProvider = await getEthereumProvider({ ..., modalType: "window" });
// or
<ArgentLoginButton options={{ ..., modalType: "window" }} />

Verify transaction requests are working properly

On zkSync 2.0, you can submit two types of transactions (legacy Ethereum transactions or custom EIP-712 type transactions), see more details here.
If you use EIP-712 type transactions, the end user won't be able to choose their fee token in their wallet, so the dapp will have to provide that functionality.
We encourage dapp developers to use the zksync-web3 SDK in their front-end:

Account abstraction support

Signature validation

Use a ERC1271-compatible library to validate signatures from your users in your smart contracts (Solidity) and front-end (JavaScript), instead of assuming a fixed signature length.
To validate signatures in smart contracts, we recommend using OpenZeppelin's SignatureChecker:
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
// ...
using SignatureChecker for address;
// ...
bool isValid = someAddress.isValidSignatureNow(messageHash, signature);
To validate signatures in the front-end, we recommend using Matter Labs' great library to abstract that logic away:
import * as zksync from "zksync-web3";
// for signed messages:
const isValid = await zksync.utils.isMessageSignatureCorrect(provider, address, message, signature);
// for typed data:
const promise = await zksync.utils.isTypedDataSignatureCorrect(provider, address, domain, types, value, signature);
Don't ignore this warning when you compile your Solidity code!

Avoid tx.origin

As recommended by Matter Labs, it shouldn't be used as it blocks smart accounts and can lead to full loss of funds for users. There are also plans to remove it from Ethereum in a future upgrade.


Smart accounts can have the ability to execute multiple transactions at once, greatly improving the user experience of dapps (for example, when you have to send 2 transactions for approve + swap on dexes).
Argent accounts have a multicall method which can be called using the following ethers interface:
const multicallInterface = new ethers.utils.Interface([
"function multicall(tuple(address to, uint256 value, bytes data)[] _transactions)",
Then, you can enable support for it in your dapp:
const signer = provider.getSigner()
const token = new ethers.Contract(..., ..., signer);
const dex = new ethers.Contract(..., ..., signer);
Without multicall:
let response = await token.approve(dex.address, INFINITE_AMOUNT); // !!
// user has to approve 1st transaction in his wallet
let result = await response.wait();
// user waits...
response = await dex.swap(token.address, otherTokenAddress, amount);
// user has to approve a 2nd transaction in his wallet
result = await response.wait();
// user waits again...
With multicall:
const accountAddress = await signer.getAddress();
const account = new ethers.Contract(accountAddress, multicallInterface, signer);
const calls = [
to: token.address,
value: 0,
data: token.interface.encodeFunctionData("approve", [dex.address, exactAmount]),
to: dex.address,
value: 0,
data: dex.interface.encodeFunctionData("swap", [token.address, otherTokenAddress, exactAmount]),
const response = await account.multicall(calls, { from: accoundAddress }); // send to account itself
const result = await response.wait();
Using multicall, the user approves just a single transaction to do a swap (as it should be), and there are no risks of lingering approvals being exploited later on.
You can detect if an account supports the multicall feature using ERC165 with the interface ID:
const interfaceId = multicallInterface.getSighash("multicall");

Need help?

If you need support, please contact [email protected]