> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# zkSync

> [card] Recommended: JavaScript SDK with React Hooks
>
> For new React apps, we recommend the JavaScript SDK with React Hooks (`@dynamic-labs-sdk/react-hooks`) instead of the legacy React SDK documented here. The JS SDK comes with many benefits such as a much smaller bundle size and other optimizations. Use the [React quickstart (JavaScript SDK)](https://docs.dynamic.xyz/docs/javascript/reference/react-quickstart.md) to get started.

> [!NOTE]
>
> This guide is currently React only.

Introducing account abstraction for zkSync enabled chains. This guide will walk you through the setup of zkSync account abstraction with comprehensive method references and transaction examples.

## Console Setup

**1. Enable zkSync Chain**

Navigate to [the EVM section of your Dynamic Console](https://console.dynamic.xyz/dashboard/chains-and-networks#evm) and toggle on a zkSync enabled chain, then click **Save**.

> [!TIP]
>
> When using zkSync with global wallets, ensure that the zkSync enabled chain is the only one selected.

**2. Configure Account Abstraction**

Go to [the Account Abstraction section](https://console.dynamic.xyz/dashboard/configurations#accountabstraction) and:

1. Enter the optional `factoryAddress`, `paymasterAddress` and `sessionKeyAddress` (if available)
2. Save the settings
3. Enable the toggle next to the **ZkSync** section

> [!WARNING]
>
> Make sure to test your configuration on testnet before deploying to mainnet.

**3. Configure Smart Contract Wallet Distribution**

Choose your SCW distribution strategy:

**Wallet Level Configuration:**

* **All Wallets**: Issue SCWs to all connected wallets (requires custom UI handling)
* **Embedded Wallets Only**: Issue SCWs only to Dynamic's embedded wallets

**User Level Configuration:**

* **All Users**: Issue SCWs to all users (existing users get SCWs on next login)
* **New Users Only**: Issue SCWs only to newly registered users

> [!NOTE]
>
> For most applications, we recommend starting with **Embedded Wallets Only** and **New Users Only** to ensure a smooth rollout.

**4. Configure Wallet Display Options**

Choose how users interact with their wallets:

* **Show Smart Wallet Only**: Users interact directly with the smart wallet
* **Show Smart Wallet & Signer**: Users can switch between the smart wallet and signer

## Installation & Setup

Install the required packages:

```bash theme={"system"}
npm install @dynamic-labs/sdk-react-core @dynamic-labs/ethereum @dynamic-labs/ethereum-aa-zksync
```

Then configure your application:

```jsx theme={"system"}
import { DynamicContextProvider, DynamicWidget } from "@dynamic-labs/sdk-react-core";
import { EthereumWalletConnectors } from "@dynamic-labs/ethereum";
import { ZkSyncSmartWalletConnectors } from "@dynamic-labs/ethereum-aa-zksync";

const App = () => (
  <DynamicContextProvider
    settings={{
      environmentId: "YOUR_ENVIRONMENT_ID",
      walletConnectors: [
        EthereumWalletConnectors,
        ZkSyncSmartWalletConnectors
      ],
    }}
  >
    <DynamicWidget />
  </DynamicContextProvider>
);

export default App;
```

> [!TIP]
>
> Use the latest compatible versions of the Dynamic SDK and provider packages. Grab your environment ID from the Dynamic Console under Developer > SDK & API Keys.

## ZKsync Connector Methods

The ZKsync connector provides several key methods for interacting with smart accounts:

### getAccountAbstractionProvider

Returns a smart account client or session client based on the provided parameters. This method is the primary way to interact with zkSync smart accounts.

```jsx theme={"system"}
import { isZKsyncConnector } from '@dynamic-labs/ethereum-aa-zksync';

// Get the smart account provider
const provider = wallet.connector.getAccountAbstractionProvider();

// Get a session-based provider
const sessionProvider = wallet.connector.getAccountAbstractionProvider({
  sessionId: 'your-session-id',
  origin: 'https://your-app.com'
});
```

### getWalletClient

Creates a wallet client with custom transport for RPC methods.

```jsx theme={"system"}
const walletClient = await wallet.getWalletClient(chainId.toString());
```

## Transaction Examples

### Basic Transaction

Send a simple transaction using the account abstraction provider:

```jsx theme={"system"}
import { isZKsyncConnector } from '@dynamic-labs/ethereum-aa-zksync';
import { useDynamicContext } from '@dynamic-labs/sdk-react-core';
import { parseEther } from 'viem';

const sendBasicTransaction = async () => {
  const { primaryWallet } = useDynamicContext();

  if (!primaryWallet?.connector || !isZKsyncConnector(primaryWallet.connector)) {
    throw new Error('ZKsync connector not found');
  }

  // Get the account abstraction provider
  const client = primaryWallet.connector.getAccountAbstractionProvider();

  if (!client) {
    throw new Error('Account abstraction client not found');
  }

  try {
    const hash = await client.sendTransaction({
      to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
      value: parseEther('0.001'),
      data: '0x'
    });

    console.log('Transaction hash:', hash);
    return hash;
  } catch (error) {
    console.error('Transaction failed:', error);
    throw error;
  }
};
```

#### Create a session

Create a session in order to make transactions on the users behalf

```jsx theme={"system"}
import { isZKsyncConnector } from '@dynamic-labs/ethereum-aa-zksync';

const generateSessionConfig = () => {
  const currentTime = BigInt(Math.floor(Date.now() / 1000));
  const oneDayPeriod = BigInt(86400);
  const defaultExpiryTime = (currentTime + oneDayPeriod).toString();

  return {
    // expiration for the whole session. If not specified, defaults to 24hrs
    expiresAt: defaultExpiryTime,
    callPolicies: [],
    feeLimit: {
      limit: parseEther('1'), // maximum fees allowed to be covered during this session
      limitType: 2, // 0 = UNLIMITED, 1 = LIFETIME, 2 = ALLOWANCE
      period: defaultExpiryTime // time before the feeLimit resets
    },
    transferPolicies: [
      {
        maxValuePerUse: parseEther('10'), // maximum amount of ETH that can be sent in a single transaction
        target: '0x....', // to address for the transfer requests
        valueLimit: parseEther('10'), // maximum amount of ETH that can be sent during the period defined below
        limitType: 2, // 0 = UNLIMITED, 1 = LIFETIME, 2 = ALLOWANCE
        period: defaultExpiryTime // time before the valueLimit resets
      }
    ]
  }
}

const createSession = async () => {
  if (!primaryWallet?.connector || !isZKsyncConnector(primaryWallet.connector)) {
    throw new Error('ZKsync connector not found');
  }

  const {
    sessionId, // session hash
    expiresAt,
    session: {
      sessionConfiguration, // session configuration w/ bigints as string
      sessionKey, // registered session private key
      sessionKeyValidator // session key validator contract address
    }
   } = await primaryWallet.connector.createSession({
    sessionConfig: generateSessionConfig(),
  });

  // ...
}
```

### Session-Based Transaction

#### Send a transaction using the session client from getAccountAbstractionProvider:

```jsx theme={"system"}
import { isZKsyncConnector } from '@dynamic-labs/ethereum-aa-zksync';
import { parseEther } from 'viem';

const sendSessionTransaction = async (sessionId, origin) => {
  if (!primaryWallet?.connector || !isZKsyncConnector(primaryWallet.connector)) {
    throw new Error('ZKsync connector not found');
  }

  // Get session-based client
  const client = primaryWallet.connector.getAccountAbstractionProvider({
    sessionId,
    origin
  });

  if (!client) {
    throw new Error('Session client not found');
  }

  try {
    const hash = await client.sendTransaction({
      to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
      value: parseEther('0.001'),
      data: '0x'
    });

    return hash;
  } catch (error) {
    console.error('Session transaction failed:', error);
    throw error;
  }
};
```

#### Send a transaction using the session client (w/o getAccountAbstractionProvider)

```jsx theme={"system"}
import { isZKsyncConnector } from '@dynamic-labs/ethereum-aa-zksync';
import { parseEther } from 'viem';

const sendSessionTransaction = async (sessionPrivateKey, sessionConfiguration) => {
  if (!primaryWallet?.connector || !isZKsyncConnector(primaryWallet.connector)) {
    throw new Error('ZKsync connector not found');
  }

  // Get session-based client
  const client = await primaryWallet.connector.createSessionClient(sessionPrivateKey, sessionConfiguration);

  if (!client) {
    throw new Error('Session client not found');
  }

  try {
    const hash = await client.sendTransaction({
      to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
      value: parseEther('0.001'),
      data: '0x'
    });

    return hash;
  } catch (error) {
    console.error('Session transaction failed:', error);
    throw error;
  }
};
```

### Message Signing

Sign messages using the smart account:

```jsx theme={"system"}
const signMessage = async (message) => {
  if (!primaryWallet?.connector || !isZKsyncConnector(primaryWallet.connector)) {
    throw new Error('ZKsync connector not found');
  }

  const client = primaryWallet.connector.getAccountAbstractionProvider();

  if (!client) {
    throw new Error('Account abstraction client not found');
  }

  try {
    const signature = await client.signMessage({
      message: message
    });

    console.log('Message signature:', signature);
    return signature;
  } catch (error) {
    console.error('Message signing failed:', error);
    throw error;
  }
};
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.