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

# Installation

WalletConnect App SDK is chain agnostic and provides seamless integration with several blockchain ecosystems. WalletConnect App SDK when combined with Universal Provider library enables compatibility across any blockchain protocol.

## Pre-requisites

This section is to inform you about the pre-requisites for integrating WalletConnect as an App with Next.js.

### Cloud Configuration

Create a new project on WalletConnect Dashboard at [https://dashboard.walletconnect.com](https://dashboard.walletconnect.com) and obtain a new project ID. You will need this project ID to initialize WalletConnect in your project (app).

<Info>
  **Don't have a project ID?**

  Head over to WalletConnect Dashboard and create a new project now!

  <Card title="Get started" href="https://dashboard.walletconnect.com/?utm_source=cloud_banner&utm_medium=docs&utm_campaign=backlinks" />
</Info>

### Allowlist

To help prevent malicious use of your project ID, you are strongly encouraged to set an allowlist of [origins](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin) where your project ID is used. You can manage your allowlist in the [WalletConnect Dashboard](https://dashboard.walletconnect.com) under the project settings.

The allowlist supports a list of origins in the format `[scheme://]<hostname[:port]>`. Using `localhost` (or `127.0.0.1`) is always permitted, and if the allowlist is empty, all origins are allowed. Updates take 15 minutes to apply.

Examples of possible origins in the allowlist:

* `example.com` - allows `https://example.com` or `http://example.com` but not `https://www.example.com`
* `https://example.com` - allows `https://example.com` but not `http://example.com`
* `https://*.example.com` - allows `https://www.example.com` but not `https://example.com`

<Warning>
  Requests from origins not in the allowlist will be denied. Make sure to add all domains where your app will be deployed.
</Warning>

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @reown/appkit @reown/appkit-universal-connector @reown/appkit-common ethers
  ```

  ```bash Yarn theme={null}
  yarn add @reown/appkit @reown/appkit-universal-connector @reown/appkit-common ethers
  ```

  ```bash Bun theme={null}
  bun add @reown/appkit @reown/appkit-universal-connector @reown/appkit-common ethers
  ```

  ```bash pnpm theme={null}
  pnpm add @reown/appkit @reown/appkit-universal-connector @reown/appkit-common ethers
  ```
</CodeGroup>

## Implementation

For a quick integration of WalletConnect App SDK you can use the `UniversalConnector` class. Which simplifies the integration of WalletConnect App SDK by providing a single interface for all the blockchain protocols.

You can configure the Universal Connector with the networks you want to support.
For more information, please visit [RPC Reference](https://docs.reown.com/advanced/multichain/rpc-reference/cosmos-rpc) section from our docs.

We recommend creating a config file to establish a singleton instance for the Universal Connector:

<CodeGroup>
  ```tsx Generic Example theme={null}
  import type { AppKitNetwork } from '@reown/appkit/networks'
  import type { CustomCaipNetwork } from '@reown/appkit-common'
  import { UniversalConnector } from '@reown/appkit-universal-connector'

  // Get projectId from https://dashboard.walletconnect.com
  export const projectId = import.meta.env.VITE_PROJECT_ID || "YOUR_PROJECT_ID_HERE" // Replace with your actual project ID

  if (!projectId || projectId === "YOUR_PROJECT_ID_HERE") {
    throw new Error('Project ID is not defined. Please set your project ID from the WalletConnect Dashboard.')
  }

  // you can configure your own network
  const suiMainnet: CustomCaipNetwork<'sui'> = {
    id: 784,
    chainNamespace: 'sui' as const,
    caipNetworkId: 'sui:mainnet',
    name: 'Sui',
    nativeCurrency: { name: 'SUI', symbol: 'SUI', decimals: 9 },
    rpcUrls: { default: { http: ['https://fullnode.mainnet.sui.io:443'] } }
  }

  export const networks = [suiMainnet] as [AppKitNetwork, ...AppKitNetwork[]]

  export async function getUniversalConnector() {
    const universalConnector = await UniversalConnector.init({
      projectId,
      metadata: {
        name: 'Universal Connector',
        description: 'Universal Connector',
        url: 'https://www.walletconnect.com',
        icons: ['https://www.walletconnect.com/icon.png']
      },
      networks: [
        {
          methods: ['sui_signPersonalMessage'],
          chains: [suiMainnet as CustomCaipNetwork],
          events: [],
          namespace: 'sui'
        }
      ]
    })

    return universalConnector
  }
  ```

  ```tsx Stacks Example theme={null}
  import type { AppKitNetwork } from '@reown/appkit/networks'
  import type { InferredCaipNetwork } from '@reown/appkit-common'
  import { UniversalConnector } from '@reown/appkit-universal-connector'

  // Get projectId from https://dashboard.walletconnect.com
  export const projectId = import.meta.env.VITE_PROJECT_ID || "YOUR_PROJECT_ID_HERE" // Replace with your actual project ID

  if (!projectId || projectId === "YOUR_PROJECT_ID_HERE") {
    throw new Error('Project ID is not defined. Please set your project ID from the WalletConnect Dashboard.')
  }

  // you can configure your own network
  const stacksMainnet: InferredCaipNetwork = {
    id: 'stacks-mainnet',
    chainNamespace: 'stacks' as const,
    caipNetworkId: 'stacks:1',
    name: 'Stacks Mainnet',
    nativeCurrency: { name: 'STX', symbol: 'STX', decimals: 6 },
    rpcUrls: { default: { http: ['https://stacks-node-api.mainnet.stacks.co'] } } // Example Stacks Mainnet RPC URL
  }

  export const networks = [stacksMainnet] as [AppKitNetwork, ...AppKitNetwork[]]

  export async function getUniversalConnector() {
    const universalConnector = await UniversalConnector.init({
      projectId,
      metadata: {
        name: 'Universal Connector',
        description: 'Universal Connector',
        url: 'https://www.walletconnect.com',
        icons: ['https://www.walletconnect.com/icon.png']
      },
      networks: [
        {
          methods: ['stx_signMessage', 'stx_signTransaction', 'stx_getAccounts', 'stx_getAddresses', 'stx_callContract', 'stx_deployContract', 'sendTransfer', 'getAddresses'],
          chains: [stacksMainnet as InferredCaipNetwork],
          events: ['stx_chainChanged', 'stx_accountsChanged'],
          namespace: 'stacks'
        }
      ]
    })

    return universalConnector
  }
  ```

  ```tsx TON Example theme={null}
  import type { AppKitNetwork } from '@reown/appkit/networks'
  import type { CustomCaipNetwork } from '@reown/appkit-common'
  import { UniversalConnector } from '@reown/appkit-universal-connector'

  // Get projectId from https://dashboard.walletconnect.com
  export const projectId = import.meta.env.VITE_PROJECT_ID || "YOUR_PROJECT_ID_HERE" // Replace with your actual project ID

  if (!projectId || projectId === "YOUR_PROJECT_ID_HERE") {
    throw new Error('Project ID is not defined. Please set your project ID from the WalletConnect Dashboard.')
  }

  const tonMainnet: CustomCaipNetwork<'ton'> = {
    id: -239,
    chainNamespace: 'ton' as const,
    caipNetworkId: 'ton:-239',
    name: 'TON',
    nativeCurrency: { name: 'TON', symbol: 'TON', decimals: 9 },
    rpcUrls: { default: { http: ['https://toncenter.com/api/v2/jsonRPC'] } }
  }

  export const networks = [tonMainnet] as [AppKitNetwork, ...AppKitNetwork[]]

  export async function getUniversalConnector() {
    const universalConnector = await UniversalConnector.init({
      projectId,
      metadata: {
        name: 'Universal Connector',
        description: 'Universal Connector',
        url: 'https://www.walletconnect.com',
        icons: ['https://www.walletconnect.com/icon.png']
      },
      networks: [
        {
          methods: ['ton_signData'],
          chains: [tonMainnet as CustomCaipNetwork],
          events: [],
          namespace: 'ton'
        }
      ]
    })

    return universalConnector
  }
  ```

  ```tsx TRON Example theme={null}
  import type { AppKitNetwork } from '@reown/appkit/networks'
  import type { CustomCaipNetwork } from '@reown/appkit-common'
  import { UniversalConnector } from '@reown/appkit-universal-connector'

  // Get projectId from https://dashboard.walletconnect.com
  export const projectId = import.meta.env.VITE_PROJECT_ID || "YOUR_PROJECT_ID_HERE" // Replace with your actual project ID

  if (!projectId || projectId === "YOUR_PROJECT_ID_HERE") {
    throw new Error('Project ID is not defined. Please set your project ID from the WalletConnect Dashboard.')
  }

  const tronMainnet: CustomCaipNetwork<'tron'> = {
    id: '0x2b6653dc',
    chainNamespace: 'tron' as const,
    caipNetworkId: 'tron:0x2b6653dc',
    name: 'Tron Mainnet',
    nativeCurrency: { name: 'TRX', symbol: 'TRX', decimals: 6 },
    rpcUrls: { default: { http: ['https://api.trongrid.io'] } }
  }

  export const networks = [tronMainnet] as [AppKitNetwork, ...AppKitNetwork[]]

  export async function getUniversalConnector() {
    const universalConnector = await UniversalConnector.init({
      projectId,
      metadata: {
        name: 'Universal Connector',
        description: 'Universal Connector',
        url: 'https://www.walletconnect.com',
        icons: ['https://www.walletconnect.com/icon.png']
      },
      networks: [
        {
          methods: ['tron_signTransaction', 'tron_signMessage'],
          chains: [tronMainnet as CustomCaipNetwork],
          events: [],
          namespace: 'tron'
        }
      ]
    })

    return universalConnector
  }
  ```
</CodeGroup>

In the App.tsx file you can add :

```tsx theme={null}
import { useState, useEffect } from 'react'
import { getUniversalConnector } from './config' // previous config file
import { UniversalConnector } from '@reown/appkit-universal-connector'

export function App() {
  const [universalConnector, setUniversalConnector] = useState<UniversalConnector>()
  const [session, setSession] = useState<any>()

  
  // Initialize the Universal Connector on component mount
  useEffect(() => {
    getUniversalConnector().then(setUniversalConnector)
  }, [])

  // Set the session state in case it changes
  useEffect(() => {
    setSession(universalConnector?.provider.session)
  }, [universalConnector?.provider.session])
```

## Trigger the modal

To open the WalletConnect modal you need to call the `connect` function from the Universal Connector.

```tsx theme={null}
    // get the session from the universal connector
    const handleConnect = async () => {
      if (!universalConnector) {
        return
      }
  
      const { session: providerSession } = await universalConnector.connect()
      setSession(providerSession)
    };

    // disconnect the universal connector
    const handleDisconnect = async () => {
      if (!universalConnector) {
        return
      }
      await universalConnector.disconnect()
      setSession(null)
    };

    ...

    return (
    (
    <div>      
        <button onClick={handleConnect}>Open WalletConnect modal</button>
        <button onClick={handleDisconnect}>Disconnect</button>
    </div>
    )
```

## Smart Contract Interaction

<Tabs>
  <Tab title="Wagmi">
    [Wagmi hooks](https://wagmi.sh/react/api/hooks/useReadContract) can help us interact with wallets and smart contracts:

    ```tsx theme={null}
    import { useReadContract } from "wagmi";
    import { USDTAbi } from "../abi/USDTAbi";

    const USDTAddress = "0x...";

    function App() {
      const result = useReadContract({
        abi: USDTAbi,
        address: USDTAddress,
        functionName: "totalSupply",
      });
    }
    ```

    Read more about Wagmi hooks for smart contract interaction [here](https://wagmi.sh/react/hooks/useReadContract).
  </Tab>

  <Tab title="Ethers">
    [Ethers](https://docs.ethers.org/v6/) can help us interact with wallets and smart contracts:

    ```tsx theme={null}
    import { useAppKitProvider, useAppKitAccount } from "@reown/appkit/react";
    import { BrowserProvider, Contract, formatUnits } from "ethers";

    const USDTAddress = "0x617f3112bf5397D0467D315cC709EF968D9ba546";

    // The ERC-20 Contract ABI, which is a common contract interface
    // for tokens (this is the Human-Readable ABI format)
    const USDTAbi = [
      "function name() view returns (string)",
      "function symbol() view returns (string)",
      "function balanceOf(address) view returns (uint)",
      "function transfer(address to, uint amount)",
      "event Transfer(address indexed from, address indexed to, uint amount)",
    ];

    function Components() {
      const { address, isConnected } = useAppKitAccount();
      const { walletProvider } = useAppKitProvider("eip155");

      async function getBalance() {
        if (!isConnected) throw Error("User disconnected");

        const ethersProvider = new BrowserProvider(walletProvider);
        const signer = await ethersProvider.getSigner();
        // The Contract object
        const USDTContract = new Contract(USDTAddress, USDTAbi, signer);
        const USDTBalance = await USDTContract.balanceOf(address);

        console.log(formatUnits(USDTBalance, 18));
      }

      return <button onClick={getBalance}>Get User Balance</button>;
    }
    ```
  </Tab>

  <Tab title="Solana">
    [@Solana/web3.js](https://solana.com/docs/clients/javascript) library allows for seamless interaction with wallets and smart contracts on the Solana blockchain.

    For a practical example of how it works, you can refer to our [lab dApp](https://lab.reown.com/appkit/?name=solana).

    ```tsx theme={null}
    import {
      SystemProgram,
      PublicKey,
      Keypair,
      Transaction,
      TransactionInstruction,
      LAMPORTS_PER_SOL
    } from '@solana/web3.js'
    import { useAppKitAccount, useAppKitProvider } from '@reown/appkit/react'
    import { useAppKitConnection, type Provider } from '@reown/appkit-adapter-solana/react'

    function deserializeCounterAccount(data?: Buffer): { count: number } {
      if (data?.byteLength !== 8) {
        throw Error('Need exactly 8 bytes to deserialize counter')
      }

      return {
        count: Number(data[0])
      }
    }

    const { address } = useAppKitAccount()
    const { connection } = useAppKitConnection()
    const { walletProvider } = useAppKitProvider<Provider>('solana')

    async function onIncrementCounter() {
      const PROGRAM_ID = new PublicKey('Cb5aXEgXptKqHHWLifvXu5BeAuVLjojQ5ypq6CfQj1hy')

      const counterKeypair = Keypair.generate()
      const counter = counterKeypair.publicKey

      const balance = await connection.getBalance(walletProvider.publicKey)
      if (balance < LAMPORTS_PER_SOL / 100) {
        throw Error('Not enough SOL in wallet')
      }

      const COUNTER_ACCOUNT_SIZE = 8
      const allocIx: TransactionInstruction = SystemProgram.createAccount({
        fromPubkey: walletProvider.publicKey,
        newAccountPubkey: counter,
        lamports: await connection.getMinimumBalanceForRentExemption(COUNTER_ACCOUNT_SIZE),
        space: COUNTER_ACCOUNT_SIZE,
        programId: PROGRAM_ID
      })

      const incrementIx: TransactionInstruction = new TransactionInstruction({
        programId: PROGRAM_ID,
        keys: [
          {
            pubkey: counter,
            isSigner: false,
            isWritable: true
          }
        ],
        data: Buffer.from([0x0])
      })

      const tx = new Transaction().add(allocIx).add(incrementIx)

      tx.feePayer = walletProvider.publicKey
      tx.recentBlockhash = (await connection.getLatestBlockhash('confirmed')).blockhash

      await walletProvider.signAndSendTransaction(tx, [counterKeypair])

      const counterAccountInfo = await connection.getAccountInfo(counter, {
        commitment: 'confirmed'
      })

      if (!counterAccountInfo) {
        throw new Error('Expected counter account to have been created')
      }

      const counterAccount = deserializeCounterAccount(counterAccountInfo?.data)

      if (counterAccount.count !== 1) {
        throw new Error('Expected count to have been 1')
      }

      console.log(`[alloc+increment] count is: ${counterAccount.count}`);
    }
    ```
  </Tab>
</Tabs>
