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

# Wallet Login

> Connect users to NEAR wallets with a secure, sandbox-based connector library

export const Github = ({url, start, end, fname, withSourceLink = true}) => {
  const [code, setCode] = useState(null);
  function toRaw(ref) {
    const fullUrl = ref.slice(ref.indexOf('https'));
    const [url] = fullUrl.split('#');
    const [org, repo, , branch, ...pathSeg] = new URL(url).pathname.split('/').slice(1);
    return `https://raw.githubusercontent.com/${org}/${repo}/${branch}/${pathSeg.join('/')}`;
  }
  async function fetchCode(url, fromLine, toLine) {
    let res;
    if (typeof window !== 'undefined') {
      const validUntil = localStorage.getItem(`${url}-until`);
      if (validUntil && Number(validUntil) > Date.now()) {
        res = localStorage.getItem(url);
      }
    }
    if (!res) {
      try {
        res = await (await fetch(url)).text();
        if (typeof window !== 'undefined') {
          localStorage.setItem(url, res);
          localStorage.setItem(`${url}-until`, String(Date.now() + 60000));
        }
      } catch {
        return 'Error fetching code, please try reloading';
      }
    }
    let body = res.split('\n');
    const from = fromLine ? Number(fromLine) - 1 : 0;
    const to = toLine ? Number(toLine) : body.length;
    body = body.slice(from, to);
    const precedingSpace = body.reduce((prev, line) => {
      if (line.length === 0) return prev;
      const spaces = line.match(/^\s+/);
      if (spaces) return Math.min(prev, spaces[0].length);
      return 0;
    }, Infinity);
    return body.map(line => line.slice(precedingSpace === Infinity ? 0 : precedingSpace)).join('\n');
  }
  function buildSourceUrl(url, start, end) {
    const base = url.split('#')[0];
    if (start && end) return `${base}#L${start}-L${end}`;
    if (start) return `${base}#L${start}`;
    return base;
  }
  useEffect(() => {
    const rawUrl = toRaw(url);
    fetchCode(rawUrl, start, end).then(res => setCode(res));
  }, [url, start, end]);
  const sourceUrl = buildSourceUrl(url, start, end);
  const startLine = start ? Number(start) : 1;
  const fileName = fname ?? sourceUrl.split('/').pop();
  return <div className="rounded-[0.625rem] border border-[#d0d7de] dark:border-[#30363d] overflow-hidden my-5 text-[0.8125rem] font-mono shadow-sm dark:shadow-[0_4px_24px_rgba(0,0,0,0.18)]">

      {}
      <div className="flex items-center justify-between py-2 px-[0.875rem] bg-[#f6f8fa] dark:bg-[#161b22] border-b border-[#d0d7de] dark:border-[#30363d]">
        <div className="flex items-center gap-2 text-[#656d76] dark:text-[#8b949e]">
          <svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor">
            <path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z" />
          </svg>
          <span className="text-xs font-medium text-[#1f2328] dark:text-[#e6edf3]">
            {fileName}
          </span>
        </div>
        {start && end && <span className="text-[0.6875rem] text-[#656d76] dark:text-[#8b949e] bg-[#eaeef2] dark:bg-[#21262d] border border-[#d0d7de] dark:border-[#30363d] rounded-full py-0.5 px-2">
            Lines {start}–{end}
          </span>}
      </div>

      {}
      <div className="overflow-auto max-h-[480px] bg-white dark:bg-[#0d1117] [&_tr]:border-b-0 [&_td]:border-b-0">
        {code === null ? <div className="py-5 px-4 text-xs text-[#656d76] dark:text-[#6e7681]">
            Loading...
          </div> : <table className="w-full border-collapse leading-[1.6]">
            <tbody>
              {code.split('\n').map((line, i) => <tr key={i} className="align-top border-0">
                  <td style={{
    minWidth: '60px'
  }} className="select-none pl-2 pr-3 text-right text-[0.7rem] text-[#8c959f] dark:text-[#3d444d] w-[1%] whitespace-nowrap border-r border-0 border-r-[#d0d7de] dark:border-r-[#21262d]">
                    {startLine + i}
                  </td>
                  <td className="pl-4 pr-6 text-[0.8125rem] text-[#1f2328] dark:text-[#e6edf3] whitespace-pre">
                    {line || ' '}
                  </td>
                </tr>)}
            </tbody>
          </table>}
      </div>

      {}
      {withSourceLink && <div className="flex justify-end py-1.5 px-[0.875rem] bg-[#f6f8fa] dark:bg-[#161b22] border-t border-[#d0d7de] dark:border-[#21262d]">
          <a href={sourceUrl} target="_blank" rel="noreferrer noopener" className="text-[0.6875rem] font-medium text-[#656d76] dark:text-[#8b949e] no-underline flex items-center gap-[0.3rem] hover:text-[#1f2328] dark:hover:text-[#e6edf3] transition-colors">
            View on GitHub
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
              <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
              <polyline points="15 3 21 3 21 9" />
              <line x1="10" y1="14" x2="21" y2="3" />
            </svg>
          </a>
        </div>}
    </div>;
};

The `@hot-labs/near-connect` library provides a secure, zero-dependency wallet connector for NEAR blockchain with a unique sandbox-based architecture.

![Preview](https://github.com/user-attachments/assets/c4422057-38bb-4cd9-8bd0-568e29f46280)

<Tip>
  **Example**

  We have a [working example](https://github.com/near-examples/hello-near-connector), which you can easily get through `create-near-app`:

  ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
  npx create-near-app@latest
  ```
</Tip>

***

## Why NEAR Connect?

Unlike traditional wallet selectors, it offers a dynamic manifest system that allows wallets to be added and updated without requiring developers to update their dependencies.

* **Secure Execution**: Wallet scripts run in isolated sandboxed iframes for maximum security
* **Dynamic Wallets**: Wallets are loaded from a manifest and can be updated without code changes
* **Zero Dependencies**: Lightweight library with no external dependencies
* **Automatic Detection**: Supports both injected wallets (extensions) and manifest-based wallets

***

## Installation

You can add the NEAR Connect library to your project in two ways:

<Tabs>
  <Tab title="library">
    Install the `@hot-labs/near-connect` and `near-api-js` packages manually:

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    npm install @hot-labs/near-connect near-api-js
    ```
  </Tab>

  <Tab title="hooks">
    If you are using React, we recommend installing the `near-connect-hooks` package which provides convenient hooks for integrating NEAR Connect into your app:

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    npm install near-connect-hooks
    ```
  </Tab>
</Tabs>

***

## Initializing the Connector

Initialize the `NearConnector` instance in your application:

<Tabs>
  <Tab title="library">
    <Github url="https://github.com/azbang/near-connect/blob/main/example/src/App.tsx" language="tsx" start="38" end="44" />
  </Tab>

  <Tab title="hooks">
    <Github url="https://github.com/near-examples/hello-near-examples/blob/main/frontend/src/pages/_app.tsx" start="8" end="19" />
  </Tab>
</Tabs>

<Accordion title="Selecting Wallets">
  Unlike traditional wallet selectors that bundle wallet code, NEAR Connect uses a **manifest-based approach**:

  1. Wallet providers register their integration scripts in a public manifest
  2. The connector dynamically loads wallet scripts when users want to connect

  This architecture eliminates the need to install individual wallet packages and ensures wallet code can be updated independently from your app.

  ```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
  connector = new NearConnector({
    network: "testnet", // or "mainnet"
    features: {
      signMessage: true,  // Only show wallets that support message signing
      signTransaction: true,
      signInWithoutAddKey: true,
      signAndSendTransaction: true,
      signAndSendTransactions: true
    },
  });
  ```
</Accordion>

***

## Signing In / Out

<Tabs>
  <Tab title="library">
    The connector uses the Observer Pattern (pub/sub), for which we need to subscribe to the `wallet:signIn" and `wallet:signOut\` events

    <Github url="https://github.com/azbang/near-connect/blob/main/example/src/App.tsx" language="tsx" start="46" end="53" />

    Then, call the `connect` function to open a modal where the user can select a wallet and sign in, and `disconnect` to sign out

    <Github url="https://github.com/azbang/near-connect/blob/main/example/src/App.tsx" language="tsx" start="74" end="77" />
  </Tab>

  <Tab title="hooks">
    The `near-connect-hooks` package provides a `useNearWallet` hook that simplifies the sign-in process, first import the hook:

    <Github url="https://github.com/near-examples/hello-near-examples/blob/main/frontend/src/components/navigation.tsx" language="tsx" start="3" end="3" />

    Then, import the `signIn` and `signOut` method from the hook and call them when needed:

    <Github url="https://github.com/near-examples/hello-near-examples/blob/main/frontend/src/components/navigation.tsx" start="9" end="22" language="tsx" />
  </Tab>
</Tabs>

***

## Calling Contract Method

<Tabs>
  <Tab title="library">
    To call a contract method, first get the connected wallet instance using `connector.wallet()`, then use the wallet's `signAndSendTransaction` method to make a function call:

    ```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
    // Get the connected wallet
    const wallet = await connector.wallet();

    // Call a change method
    const result = await wallet.signAndSendTransaction({
      receiverId: "hello.near-examples.testnet",
      actions: [
        {
          type: "FunctionCall",
          params: {
            methodName: "set_greeting",
            args: { greeting: "Hello from NEAR Connect!" },
            gas: "30000000000000", // 30 TGas
            deposit: "0", // No deposit
          },
        },
      ],
    });

    console.log("Transaction:", result.transaction.hash);
    ```
  </Tab>

  <Tab title="hooks">
    To call a contract method, you can use the `callFunction` method provided by the `useNearWallet` hook:

    <Github url="https://github.com/near-examples/hello-near-examples/blob/main/frontend/src/pages/hello-near/index.tsx" start="27" end="27" language="tsx" />
  </Tab>
</Tabs>

***

## Calling Read-only Methods

<Tabs>
  <Tab title="library">
    The `near-connector` does not provide a built-in way to call read-only (view) methods.

    However, you can use the `near-api-js` package (or any of your preferred APIs) to create a JSON-RPC provider and call view methods directly:

    ```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
    import { JsonRpcProvider } from "near-api-js";

    const provider = new JsonRpcProvider({ url: "https://test.rpc.fastnear.com" });

    const greeting = await provider.callFunction(
      "hello.near-examples.testnet",
      "get_greeting",
      {}
    );
    ```
  </Tab>

  <Tab title="hooks">
    You can use the `viewFunction` method provided by the `useNearWallet` hook to call read-only methods on the contract:

    <Github url="https://github.com/near-examples/hello-near-examples/blob/main/frontend/src/pages/hello-near/index.tsx" language="tsx" start="18" end="18" />
  </Tab>
</Tabs>

***

## Get Balance

<Tabs>
  <Tab title="library">
    The `near-connector` does not provide a built-in way to get the account balance.

    However, you can use the `near-api-js` package (or any of your preferred APIs) to create a JSON-RPC provider and query the account balance directly:

    ```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
    import { JsonRpcProvider } from "near-api-js";

    const provider = new JsonRpcProvider({ url: "https://test.rpc.fastnear.com" });

    const greeting = await provider.viewAccount({ accountId: "hello.near-examples.testnet" });
    ```
  </Tab>

  <Tab title="hooks">
    You can use the `getBalance` method provided by the `useNearWallet` hook to call read-only methods on the contract:

    ```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
    import { useNearWallet } from 'near-connect-hooks';
    import { yoctoToNear } from 'near-api-js';

    const { getBalance } = useNearWallet();
    const balance = await getBalance();
    console.log(`Balance: ${yoctoToNear(balance.available, 2)} NEAR`);
    ```
  </Tab>
</Tabs>

***

## Send Multiple Transactions

<Tabs>
  <Tab title="library">
    You can request the user to sign and send multiple transactions in parallel through a single prompt:

    ```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
    const wallet = await connector.wallet();

    const results = await wallet.signAndSendTransactions({
      transactions: [
        {
          receiverId: "token.near",
          actions: [
            {
              type: "FunctionCall",
              params: {
                methodName: "ft_transfer",
                args: {
                  receiver_id: "alice.near",
                  amount: "1000000",
                },
                gas: "30000000000000",
                deposit: "1", // 1 yoctoNEAR for security
              },
            },
          ],
        },
        {
          receiverId: "nft.near",
          actions: [
            {
              type: "FunctionCall",
              params: {
                methodName: "nft_mint",
                args: {
                  token_id: "token-1",
                  receiver_id: "alice.near",
                },
                gas: "30000000000000",
                deposit: "10000000000000000000000", // 0.01 NEAR
              },
            },
          ],
        },
      ],
    });

    console.log(`Completed ${results.length} transactions`);
    ```
  </Tab>

  <Tab title="hooks">
    You can use the `signAndSendTransactions` method provided by the `useNearWallet` hook to send multiple transactions in a single request:

    ```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
    import { useNearWallet } from 'near-connect-hooks';

    ...

    const { signAndSendTransactions } = useNearWallet();

    const results = await signAndSendTransactions({
      transactions: [
        {
          receiverId: "token.near",
          actions: [
            {
              type: "FunctionCall",
              params: {
                methodName: "ft_transfer",
                args: {
                  receiver_id: "alice.near",
                  amount: "1000000",
                },
                gas: "30000000000000",
                deposit: "1", // 1 yoctoNEAR for security
              },
            },
          ],
        },
        {
          receiverId: "nft.near",
          actions: [
            {
              type: "FunctionCall",
              params: {
                methodName: "nft_mint",
                args: {
                  token_id: "token-1",
                  receiver_id: "alice.near",
                },
                gas: "30000000000000",
                deposit: "10000000000000000000000", // 0.01 NEAR
              },
            },
          ],
        },
      ],
    });
    console.log(`Completed ${results.length} transactions`);
    ```
  </Tab>
</Tabs>

***

### Sign Messages (NEP-413)

In NEAR, users can sign messages for authentication purposes without needing to send a transaction:

<Tabs>
  <Tab title="library">
    You can request the user to sign a message using the wallet's `signMessage` method:

    ```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
    const wallet = await connector.wallet();

    const signature = await wallet.signMessage({
      message: "Please sign this message to authenticate",
      recipient: "your-app.near",
      nonce: Buffer.from(crypto.randomUUID()),
    });

    console.log("Signature:", signature.signature);
    console.log("Public Key:", signature.publicKey);

    // Verify the signature on your backend
    ```
  </Tab>

  <Tab title="hooks">
    You can use the `signMessage` method provided by the `useNearWallet` hook to request the user to sign a message:

    ```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
    import { useNearWallet } from 'near-connect-hooks';

    ...

    const { signNEP413Message } = useNearWallet();

    const signature = await signMessage({
      message: "Please sign this message to authenticate",
      recipient: "your-app.near",
      nonce: Buffer.from(crypto.randomUUID()),
    });

    console.log("Signature:", signature.signature);
    console.log("Public Key:", signature.publicKey);
    ```
  </Tab>
</Tabs>
